python學習日記(包——package)
簡述——包
包是一種通過使用‘.模組名’來組織python模組名稱空間的方式。
注意:
1. 無論是import形式還是from...import形式,凡是在匯入語句中(而不是在使用時)遇到帶點的,都要第一時間提高警覺:這是關於包才有的匯入語法
2. 包是目錄級的(資料夾級),資料夾是用來組成py檔案(包的本質就是一個包含__init__.py檔案的目錄)
3. import匯入檔案時,產生名稱空間中的名字來源於檔案,import 包,產生的名稱空間的名字同樣來源於檔案,即包下的__init__.py,匯入包本質就是在匯入該檔案
強調:
1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯
2. 建立包的目的不是為了執行,而是被匯入使用,記住,包只是模組的一種形式而已,包即模組
包A和包B下有同名模組也不會衝突,如A.a與B.a來自兩個名稱空間
import os os.makedirs('glance/api') os.makedirs('glance/cmd') os.makedirs('glance/db') l = []#注意列表的用法與作用 l.append(open('glance/__init__.py','w')) l.append(open('glance/api/__init__.py','w')) l.append(open(建立目錄層次程式碼'glance/api/policy.py','w')) l.append(open('glance/api/versions.py','w')) l.append(open('glance/cmd/__init__.py','w')) l.append(open('glance/cmd/manage.py','w')) l.append(open('glance/db/models.py','w')) l.append(open('glance/db/__init__.py','w')) map(lambda f:f.close() ,l)#同時關閉多個檔案
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那必須使用後者。
import
在與包glance同級別的檔案中測試
import glance.api.policy glance.api.policy.get()
from...import...
需要注意的是from後import匯入的模組,必須是明確的一個不能帶點,否則會有語法錯誤,如:from a import b.c是錯誤語法
我們在與包glance同級別的檔案中測試
from glance.db import models models.register_models('abc') from glance.cmd.manage import main main()
__init__.py檔案
不管是哪種方式,只要是第一次匯入包或者是包的任何其他部分,都會依次執行包下的__init__.py檔案(我們可以在每個包的檔案內都列印一行內容來驗證一下),這個檔案可以為空,但是也可以存放一些初始化包的程式碼。
with open('glance\__init__.py',encoding='utf-8') as f: print(f.readline()) import glance
from glance.api import *
在講模組時,我們已經討論過了從一個模組內匯入所有*,此處我們研究從一個包匯入所有*。
此處是想從包api中匯入所有,實際上該語句只會匯入包api下__init__.py檔案中定義的名字,我們可以在這個檔案中定義__all___:
#在api\__init__.py裡 x = 100 def f(): print('from api.__init__.py',x) __all__ = ['x','policy','f']
此時我們在與glance同級的檔案中執行from glance.api import *就匯入__all__中的內容(versions仍然不能匯入)。
from glance.api import * policy.get() f()
追加(注意)
如果想要這樣呼叫(glance同級檔案下)
import glance glance.api.policy.get()
需要在__init__檔案裡面新增一些初始程式,如下:
#在glance\__init__.py from glance import api #在api\__init__.py from glance.api import policy
絕對匯入(sys.path)和相對匯入
概述
ps:在上面追加的基礎上↑
我們的最頂級包glance是寫給別人用的,然後在glance包內部也會有彼此之間互相匯入的需求,這時候就有絕對匯入和相對匯入兩種方式:
絕對匯入:以glance作為起始
相對匯入:用.或者..的方式最為起始(只能在一個包中使用,不能用於不同目錄內)
例如:我們在glance/api/version.py中想要匯入glance/cmd/manage.py
在glance/api/version.py #絕對匯入 from glance.cmd import manage manage.main() #相對匯入 from ..cmd import manage manage.main()
測試結果:注意一定要在於glance同級的檔案中測試
from glance.api import versions
注意!!
特別需要注意的是:可以用import匯入內建或者第三方模組(已經在sys.path中),但是要絕對避免使用import來匯入自定義包的子模組(沒有在sys.path中),應該使用from... import ...的絕對或者相對匯入,且包的相對匯入只能用from的形式。
比如我們想在glance/api/versions.py中匯入glance/api/policy.py,有的人一看這兩個模組是在同一個目錄下,他是這樣做的:
#在version.py中 import policy policy.get()
沒錯,我們單獨執行version.py是一點問題沒有的,執行version.py的路徑搜尋就是從當前路徑開始的,於是在匯入policy時能在當前目錄下找到。
但是同時,子包中的模組version.py極有可能是被一個glance包同一級別的其他檔案匯入,比如我們在於glance同級下的一個test.py檔案中匯入version.py,如下:
from glance.api import versions ''' 執行結果: ImportError: No module named 'policy' ''' ''' 分析: 此時我們匯入versions在versions.py中執行 import policy需要找從sys.path也就是從當前目錄找policy.py, 這必然是找不到的 '''
————————分割線————————
glance/ ├── __init__.py from glance import api from glance import cmd from glance import db ├── api │ ├── __init__.py from glance.api import policy from glance.api import versions │ ├── policy.py │ └── versions.py ├── cmd from glance.cmd import manage │ ├── __init__.py │ └── manage.py └── db from glance.db import models ├── __init__.py └── models.py絕對匯入
glance/ ├── __init__.py from . import api #.表示當前目錄 from . import cmd from . import db ├── api │ ├── __init__.py from . import policy from . import versions │ ├── policy.py │ └── versions.py ├── cmd from . import manage │ ├── __init__.py │ └── manage.py from ..api import policy #..表示上一級目錄,想再manage中使用policy中的方法就需要回到上一級glance目錄往下找api包,從api匯入policy └── db from . import models ├── __init__.py └── models.py相對匯入
單獨匯入包
單獨匯入的結果
單獨匯入包名稱時不會匯入包中所有包含的所有子模組,如
import glance glance.api.policy.get()
解決方法:
#在glance\__init__.py from . import api #在api\__init__.py from . import policy
重新執行程式碼就OK了。
import glance之後直接呼叫模組中的方法
glance/ ├── __init__.py from .api import * from .cmd import * from .db import * ├── api │ ├── __init__.py __all__ = ['policy','versions'] │ ├── policy.py │ └── versions.py ├── cmd __all__ = ['manage'] │ ├── __init__.py │ └── manage.py └── db __all__ = ['models'] ├── __init__.py └── models.py import glance policy.get()#好像不行? import glance glance.policy.get()#View Code
pass