1、標準 importpython
Python中全部加載到內存的模塊都存放在 sys.modules 列表中。緩存
當import xxx 一個模塊時,首先去 sys.modules 列表中查找是否已經加載了 xxx模塊,bash
若是已經加載了,就把模塊名字xxx 加入到正在調用 import xxx 模塊的 Local 名字空間中。app
若是沒有加載,則從 sys.path 目錄中按照模塊名稱查找模塊文件,模塊能夠是py、pyc、pyd,找到後將模塊載入內存,並加到 sys.modules 中,並將名稱導入到當前的 Local 名字空間。函數
一個模塊不會重複導入,多個不一樣的模塊均可以用 import 引入同一個模塊到本身的 Local 名字空間中。編碼
import 只能導入模塊,不能導入模塊中的 對象(函數、類、變量等);url
例如:模塊 A 中 有一個函數 getName(),另外一個模塊不能經過 import A.getName 將 getName 導入到本模塊,只能用 from A import getName。spa
2、嵌套 importcode
(1)順序嵌套。orm
本模塊導入A模塊(import A),A中又 import B,B模塊又 import 其餘模塊 ....
本模塊 import A 後,本模塊只能訪問A,不能訪問 模塊B 以及 其餘模塊,即便 B模塊已經加載在內存中,若是訪問還要在本模塊中 import B。
(2)循環嵌套。
文件[ A.py ]
from B import D
class C: pass
文件[ B.py ]
from A import C
class D: pass
當執行文件 A.py 到 import D時會報錯,可是將文件[ A.py ],修改成 import B 便可。
當執行語句 from B import D 時,分爲如下步驟:
1)在 sys.modules 中查找符號 「B」
2)若是符號 「B」 存在,則直接得到 符號 「B」 對應的 module 對象。
從 <module B> 對象的 __dict__ 中得到符號 「D」 對應的對象,若是 「D」 不存在,則拋出異常。
3)若是符號 「B」 不存在,則建立一個新的 module 對象, <module B> ,此時 <module B> 的 __dict__ 爲空,
執行[ B.py ] 中的表達式,填充 <module B> 的 __dict__ ,
從 <module B> 對象的 __dict__ 中得到符號 「D」 對應的對象,若是 「D」 不存在,則拋出異常。
例子中的執行順序爲:
(1)先執行 A.py 中的 from B import D,因爲是執行的 python A.py ,因此 sys.modules 中並無 <module B>,首先爲 B.py 建立一個module對象( <module B> ),
此時,module 對象是空的,而後解析執行 B.py。
(2)轉去執行 B.py 中的 from A import C,首先檢查 sys.modules 是否存在 <module A>,因爲此時尚未緩存 <module A> ,因此相似的,Python內部爲 A.py 建立一個 module 對象( <module A>),而後一樣轉去執行 A.py中的語句。
(3)再次執行 A.py 中的 from B import D 時,因爲在第(1)步建立的 <module B> 對象,已經緩存在 sys.modules 中,因此直接就獲得了 <module B>,可是<module B>,依舊是一個空對象,當從<module B> 獲取 符號 「D」 時,就會拋出異常。若是這裏是 import B,因爲符號 「B」 在 sys.modules 中已經存在,因此不會拋出異常。
3、包 import
只要一個文件夾下面有 __init__.py 文件,這個文件夾就能夠看作包。
包的導入過程和模塊基本一致,只是導入包的過程當中,先執行包目錄下的 __init__.py。
若是隻是單純的導入包,而包的 __init__.py 中沒有其餘初始化的操做,那麼此包下面的模塊是不會自動導入的。
1、把模塊按層次結構組織成包
建立一個軟件包在目錄中定義一個__init__.py文件。
__init__.py文件的目的就是包含可選的初始化代碼,當遇到軟件包中不一樣層次的模塊時會觸發運行。
對於導入語句:>>> import graphics.formats.jpg
文件graphics/__init__.py 和 graphics/formats/__init__.py 都會在導入文件graphics/formats/jpg.py以前優先獲得導入!
大部分狀況下,把__init__.py文件留空也是能夠的。可是,在某些特定的狀況下__init__.py文件可用來加載子模塊。
# graphics/formats/__init__.py from . import jpg from . import png
2、對全部符號的導入進行控制
使用>>> from module import * 語句時,在模塊中定義__all__,那麼只有顯式列出的符號名纔會被導出。
若是將__all__定義成一個空列表,那麼任何符號都不會被導出。
若是__all__包含有未定義的名稱,那麼在執行import語句時會產生一個AttributeError異常。
__all__ = [ 'spam', 'grok' ]
3、用相對名稱來導入包中的子模塊
要在軟件包的子模塊中導入同一個包中其餘的子模塊,請使用相對名稱來導入。
mypackage/ __init__.py A/ __init__.py spam.py grok.py B/ __init__.py bar.py
若是模塊mypackage.A.spam要導入位於同一個目錄中的模塊grok,應該使用
>>> from . import grok
若是模塊mypackage.A.spam要導入位於不一樣目錄中的模塊 B.bar,應該使用
>>> from ..B import bar
>>> from mypacksge.A import grok
使用絕對名稱的缺點在於這麼作會將最頂層的包名稱硬編碼到源代碼中,這使得代碼更加脆弱,若是想從新組織一下結構會比較困難。
▲ 一切包的相對導入都是在主程序所在目錄之下進行的,不能導入它的上一級目錄中的包。
▲ 位於腳本頂層的模塊不能使用相對導入。
▲ 包的某個部分是直接以腳本的形式執行的,這種狀況下也不能使用相對導入。
4、將模塊分解成多個文件
能夠經過將模塊轉換爲包的方式將模塊分解成多個單獨的文件。
# mymodule.py class A: def spam(self): print('A.spam') class B(A): def bar(self): print('B.bar')
把mymodule.py分解爲兩個文件,每一個文件包含一個類的定義。
mymodule/ __init__.py a.py b.py # a.py class A: def spam(self): print('A.spam') # b.py from .a import A class B(A): def bar(self): print('B.bar') # __init__.py from .a import A from .b import B
建立一個包目錄,並經過__init__.py文件將各個部分粘合在一塊兒。
引入惰性導入的概念。__init__.py文件一次性將全部須要的組件都導入進來。
若是隻但願在實際須要的時候才加載那些組件。爲了實現這個目的,下面對__init__.py文件作了修改:
# __init__.py def A(): from .a import A return A() def B(): from .b import B return B()
惰性加載的主要缺點在於會破壞繼承和類型檢查機制。
>>> if isinstance(x, mymodule.A): # Error
>>> if isinstance(x, mymodule.a.A): # OK
5、讓各個目錄下的代碼在統一的命名空間下導入
使各個單獨的目錄統一在一個公共的命名空間下,能夠把代碼像普通的Python包那樣進行組織。
可是對於打算合併在一塊兒的組件,這些目錄中的__init__.py文件則須要忽略。
foo-package/ spam/ blah.py bar-package/ spam/ grok.py
spam同來做爲公共的命名空間。注意這兩個目錄中都沒有出現__init__.py文件。
將foo-package和bar-package都添加到Python的模塊查詢路徑中,而後嘗試作一些導入操做。
>>> sys.path.extend(['foo-package', 'bar-package'])
>>> import spam.blah
>>> import spam.grok
兩個不一樣的包目錄合併在了一塊兒,能夠隨意導入spam.blah或者spam.grok。
原理:
使用了命名空間包的特性。
命名空間包是一種特殊的包,用來合併不一樣目錄下的代碼,把他們放在統一的命名空間之下進行管理。
關鍵在於確保統一命名空間的頂層目錄不包含__init__.py文件。
命名空間包的一個重要特性是任何人均可以用本身的代碼來擴展命名空間中的內容。
每一個包都在__file__模塊中保存了全路徑。
若是缺乏__file__屬性,這個包就是命名空間。
6、從新加載模塊
從新加載一個已經加載過了的模塊,使用imp.reload()
>>> import spam
>>> import imp
>>> imp.reload(spam)
可是,reload()操做不會更新 from module import xxx 這樣的語句導入的定義。
7、讓目錄或zip文件稱爲可運行的腳本
建立一個目錄或zip文件,在其中添加一個__main__.py,這是一種打包規模較大的Python應用程序的可行方法。
8、讀取包中的數據文件
包的結構:
mypackage/ __init__.py somedata.dat spam.py
>>> import pkgutil
>>> data = pkgutil.get_data(__package__, 'somedata.dat')
get_data()的第一個參數是包含有包名的字符串。咱們能夠直接提供這個字符串,或者使用__package__這個特殊變量。
第二個參數是要獲取的文件相對於包的名稱。
9、添加目錄到sys.path中
建立一個.pth文件,將目錄寫出來:
# myapplication.pth /some/dir /other/dir
這個.pth文件須要放在Python的其中一個site-packages目錄中,通常來講位於/usr/local/lib/python3.3/site-packages。
在解釋器啓動的時候,只要.pth文件中列出的目錄存在於文件系統中,那麼它們就會被添加到sys.path中。
10、使用字符串中給定的名稱來導入模塊
當模塊或包的名稱以字符串的形式給出時,可使用importlib.import_module()函數來手動導入這個模塊。
>>> import importlib
>>> math = importlib.import_module('math')
>>> math.sin(2)
導入包 from . import b 的用法:
>>> b = importlib.import_module('.b', __package__)
十3、安裝只爲本身所用的包
Python有一個用戶級的安裝目錄,一般位於~./local/lib/python3.3/site-packages這樣的目錄下。
python3 setup.py install -user 或者
pip install --user packagename
用戶級的site-package目錄一般會在sys.path中出現,並且位於系統級的site-package目錄以前。
所以,採用這種技術安裝的包比已經安裝到系統中的包優先級要高
十4、建立新的Python環境
經過pyvenv命令建立一個新的虛擬環境。
bash % pyvenv Spam
Spam目錄下會建立出 bin、include、lib、pyvene.cfg目錄,而且在bin目錄下有一個可以使用的Python解釋器。
bash % Spam/bin/python3
建立虛擬環境大部分緣由都是爲了安裝和管理第三方的包。
下一步一般是安裝一個包管理器,distribute或者pip
若是想將已經安裝過的包引入,使其做爲虛擬環境的一部分,那麼可使用--system-site-packages來建立虛擬環境。
bash % pyvenv --system-site-packages Spam
十5、發佈自定義的包
把編寫的庫分發給其餘人使用。
典型的程序庫結構:
projectname/ README.txt Doc/ documentation.txt projectname/ __init__.py foo.py bar.py utils/ __init__.py spam.py grok.py examples/ hellworld.py
首先編寫一個setup.py文件。
from distutils.core import setup setup(name='projectname', varsion='1.0', author='Your Name', author_email='you@youaddress.com', url='http://www.you.com/projectname', packages=['projectname', 'projectname.utils'] )
須要手動列出包中的每個子目錄:packages=['projectname', 'projectname.utils']
接下來建立一個MANIFEST.in文件。列出各類但願包含在包中的非源代碼文件:
# MANIFEST.in include *.txt recursive-include examples * recursive-include Doc *
確保setup.py和MANIFEST.in文件位於包的頂層目錄。
% bash python3 setup.py sdist
系統會建立出projectname-1.0.zip或者projectname-1.0.tar.gz這樣的文件。