一個模塊就是一個包含了python定義和聲明的文件,文件名就是模塊名字加上.py的後綴。
隨着程序的發展,功能愈來愈多,爲了方便管理,咱們一般將程序分紅一個個的文件,這樣作程序的結構更清晰,方便管理。這時咱們不只僅能夠把這些文件當作腳本去執行,還能夠把他們當作模塊來導入到其餘的模塊中,實現了功能的重複利用
樣例文件:spam.py,文件名spam.py,模塊名spam
#!/usr/bin/env python #-*- coding:utf-8 -*- #spam.py print('from the spam.py') money=10000 def read1(): print('spam->read1->money',money) def read2(): print('spam->read2') read1() def change(): global money money=0 if __name__ == '__main__': print("文件被當作腳本執行")
模塊能夠包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第一次遇到導入import語句時才執行(import語句是能夠在程序中的任意位置使用的,且針對同一個模塊很import屢次,爲了防止你重複導入,python的優化手段是:第一次導入後就將模塊名加載到內存了,後續的import語句僅是對已經加載大內存中的模塊對象增長了一次引用,不會從新執行模塊內的語句),以下python
test.py import spam import spam import spam ''' 打印結果爲 from the spam.py '''
#!/usr/bin/env python #-*- coding:utf-8 -*- import sys import spam money=10 print(spam.money) #這個是調用的spam下的money變量 def read1(): print("=======") spam.read1() money=1 spam.change() print(money) #這個結果是本地的money 執行結果爲 from the spam.py 10000 spam->read1->money 10000 1
一、爲源文件(spam模塊)建立新的名稱空間,在spam中定義的函數和方法如果使用到了global時訪問的就是這個名稱空間。
二、在新建立的命名空間中執行模塊中包含的代碼,見初始導入import spam
三、建立名字spam來引用該命名空間mysql
這個名字和變量名沒什麼區別,都是‘第一類的’,且使用spam.名字的方式能夠訪問spam.py文件中定義的名字,spam.名字與test.py中的名字來自兩個徹底不一樣的地方。
import spam as sp sp.read1() print(sp.money) 執行結果爲: from the spam.py spam->read1->money 10000 10000
from spam import read1,read2,change,money #這樣在當前位置直接使用read1和read2就行了,執行時,仍然以spam.py文件全局名稱空間 change() read2()
若是當前有重名read1或者read2,那麼會有覆蓋效果。sql
from spam import read1 def read1(): print('==========') read1() 打印結果爲: from the spam.py ==========
from spam import * ##將模塊spam中全部的名字都導入到當前名稱空間 print(money) print(read1) print(read2) print(change) 打印結果爲: from the spam.py 10000 <function read1 at 0x000000000089CC80> <function read2 at 0x000000000089CBF8> <function change at 0x000000000089CD08>
能夠是使用__all__來控制*api
__all__=['read1','money'] #再使用*導入時,只能有這兩個方法能夠調用 print('from the spam.py') money=10000 def read1(): print('spam->read1->money',money) def read2(): print('spam->read2') read1() def change(): global money money=0 if __name__ == '__main__': print("文件被當作腳本執行")
模塊的查找順序是:內存中已經加載的模塊->內置模塊->sys.path路徑中包含的模塊
包是一種經過使用‘.模塊名’來組織python模塊名稱空間的方式。不管是import形式仍是from...import形式,凡是在導入語句中(而不是在使用時)遇到帶點的,都要第一時間提升警覺:這是關於包纔有的導入語法, 包的本質就是一個包含__init__.py文件的目錄。 包A和包B下有同名模塊也不會衝突,如A.a與B.a來自倆個命名空間
glance/ #Top-level package ├── __init__.py #Initialize the glance package ├── api #Subpackage for api │ ├── __init__.py │ ├── policy.py │ └── versions.py ├── cmd #Subpackage for cmd │ ├── __init__.py │ └── manage.py └── db #Subpackage for db ├── __init__.py └── models.py 複製代碼
#文件內容 #policy.py def get(): print('from policy.py') #versions.py def create_resource(conf): print('from version.py: ',conf) #manage.py def main(): print('from manage.py') #models.py def register_models(engine): print('from models.py: ',engine)
1.關於包相關的導入語句也分爲import和from ... import ...兩種,可是不管哪一種,不管在什麼位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,不然非法。能夠帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。函數
2.對於導入後,在使用時就沒有這種限制了,點的左邊能夠是包,模塊,函數,類(它們均可以用點的方式調用本身的屬性)。性能
3.對比import item 和from item import name的應用場景:
若是咱們想直接使用name那必須使用後者。測試
在包glance文件中測試優化
import glance.db.models glance.db.models.register_models('mysql') 打印結果爲: from models.py: mysql
須要注意的是from後import導入的模塊,必須是明確的一個不能帶點,不然會有語法錯誤,如:from a import b.c是錯誤語法spa
咱們在與包glance同級別的文件中測試code
from glance.db import models #把文化做爲模塊調用 models.register_models('mysql') from glance.db.models import register_models #模塊的方法調用過來 register_models('mysql') from models.py: mysql from models.py: mysql
不論是哪一種方式,只要是第一次導入包或者是包的任何其餘部分,都會依次執行包下的__init__.py文件,這個文件能夠爲空,可是也能夠存放一些初始化包的代碼。
此處是想從包api中導入全部,實際上該語句只會導入包api下__init.py文件中定義的名字,咱們能夠在這個文件中定義_all:
#!/usr/bin/env python #-*- coding:utf-8 -*- #在api 的__init__.py中定義 x=10 def func(): print('from api.__init.py') __all__=['x','func','policy']
此時咱們在於glance同級的文件中執行from glance.api import *就導入__all__中的內容(versions仍然不能導入)。
from glance.api import * #這個*表明的是glance.api下的__init__.py文件中的__all__中定義的方法 print(x) #init中定義的x變量 func() #init中定義的func函數 policy.get() #policy裏的get函數 打印結果爲: 10 from api.__init.py from policy.py
最頂級包glance是寫給別人用的,而後在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:
絕對導入:以glance做爲起始
相對導入:用.或者..的方式最爲起始(只能在一個包中使用,不能用於不一樣目錄內)
例如:咱們在glance/api/version.py中想要導入glance/cmd/manage.py
from glance.cmd import manage #絕對導入 manage.main() from ..cmd import manage #至關導入 manage.main()
單獨導入包名稱時不會導入包中全部包含的全部子模塊,如
#在與glance同級的test.py中 import glance glance.cmd.manage.main() ''' 執行結果: AttributeError: module 'glance' has no attribute 'cmd' '''
解決方法:
1 #glance/__init__.py 2 from . import cmd 3 4 #glance/cmd/__init__.py 5 from . import manage
#glance的同級目錄下的test.py import glance glance.cmd.manage.main()