標籤:ada 就會 one 檔案 二層 closed main not img
1、什麼是包
#官網解釋
Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一種通過使用‘.模組名’來組織python模組名稱空間的方式。
#具體的:包就是一個包含有__init__.py檔案的檔案夾,所以其實我們建立包的目的就是為了用檔案夾將檔案/模組組織起來
#需要強調的是:
1. 在python3中,即使包下沒有__init__.py檔案,import 包仍然不會報錯,而在python2中,包下一定要有該檔案,否則import 包報錯
2. 建立包的目的不是為了運行,而是被匯入使用,記住,包只是模組的一種形式而已,包的本質就是一種模組
2、為何要使用包
包的本質就是一個檔案夾,那麼檔案夾唯一的功能就是將檔案組織起來
隨著功能越寫越多,我們無法將所以功能都放到一個檔案中,於是我們使用模組去組織功能,而隨著模組越來越多,我們就需要用檔案夾將模組檔案組織起來,以此來提高程式的結構性和可維護性
3、注意事項
#1、關於包相關的匯入語句也分為import和from ... import ...兩種,但是無論哪種,無論在什麼位置,在匯入時都必須遵循一個原則:凡是在匯入時帶點的,點的左邊都必須是一個包,否則非法。可以帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。但對於匯入後,在使用時就沒有這種限制了,點的左邊可以是包,模組,函數,類(它們都可以用點的方式調用自己的屬性)。
例:import spam.x
匯入前:import spam.x:如果 spam 是一個模組,就會報錯,spam 必須是一個包
匯入後:spam.x 直接調用模組 spam 下的 x 屬性
#2、import匯入檔案時,產生名稱空間中的名字來源於檔案,import 包,產生的名稱空間的名字同樣來源於檔案,即包下的__init__.py,匯入包本質就是在匯入該檔案
調用包就是執行包下的__init__.py檔案
#3、包A和包B下有同名模組也不會衝突,如A.a與B.a來自倆個命名空間
4、例子
例1:
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.pydef get(): print(‘from policy.py‘)#versions.pydef create_resource(conf): print(‘from version.py: ‘,conf)#manage.pydef main(): print(‘from manage.py‘)#models.pydef register_models(engine): print(‘from models.py: ‘,engine)包所包含的檔案內容
檔案內容
from . import api# 告訴調用 glance 包的模組,找api 的話從你自己的 sys.path 下 glance 下開始找 api
glance包 __init__ 的檔案內容
# print(‘from api init.py‘)# __all__=[‘x‘,‘y‘,‘policy‘] # all 方法對應 # x=1# y=2from . import policy# 告訴那個匯入 api包的模組(test),找 policy 的時候,從他自己的 sys.path 開始找# import policy# 絕對匯入# 告訴那個匯入 api包的模組(test),找 policy 的時候,從他自己的 sys.path 下的 glance.api 開始找# from glance.api import policy# 相對匯入# 從目前的目錄開始找 policy 模組# from . import policy# 幫 test 找到 manage 模組# from ..cmd import manage# 直接運行此檔案會報錯,# SystemError: Parent module ‘‘ not loaded, cannot perform relative import# 父模組沒有被載入,不能使用相對匯入的意思# 說明包裡面的模組不應該作為單獨檔案直接運行
api包 __init__ 的檔案內容
# 例1:直接 import 包方式匯入模組# import glance.api.policy # 匯入 blance包下的api包下的policy模組# glance.api.policy.get() # 執行 policy下的 get 方法# 例2:比較直觀的用法# from glance.api import policy # from 大包.小包 import 模組# policy.get()# from glance.api import policy.get # 不能這樣用,報 SyntaxError: invalid syntax 語法錯誤# get()# from glance import api.policy# 雖然滿足點左邊的是包,但是這裡是 from ... import,import後面必須明確一個不能帶點的東西#需要注意的是from後import匯入的模組,必須是明確的一個不能帶點東西,否則會有語法錯誤# 如:from a import b.c 是錯誤文法# api 的 init 檔案# from glance.api import policy# 當匯入包的時候,只會執行 api 包下面的 init 檔案# policy.get()# * 的意義# from glance.api import *# 匯入包,依然會執行 init 檔案,但是這裡的 * 不代表 api 包下所有的模組# * 是指 api 下 init 裡面 __all__ 裡麵包含的屬性,屬性可以是任何,模組,變數等等# import glance.api # 匯入包就執行 glance 和 api 包 init 檔案# print(glance.api.policy)# 但是 policy 依然沒有,因為這裡只是匯入包,執行 init,不會觸發 all 方法# import glance.api # 觸發 api 下的 init 檔案# print(glance.api.policy) # ImportError: No module named ‘policy‘# init 下有 import policy# 先從記憶體裡找 policy,然後從內建裡找,最後從當前 test 所在的 sys.path 裡找 policy 模組,找不到,報錯# 讓 api 包幫我找到 manage 模組# glance.api.manage.main()import glanceglance.api.policy.get()# 如果是匯入跟“包”同級的aaa包下的 glacne,就要先找到兩者的父級目錄,再從父級目錄開始找import osimport sysbase_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))print(base_dir) # 父級目錄sys.path.append(base_dir)from aaa.glance.api import policypolicy.get()
跟 glance 同級的檔案 test.py
例2:
if __name__==‘__main__‘: # 表示把自己當做指令碼去用 print(‘ok‘)
如果我們是直接執行某個.py檔案的時候,該檔案中那麼”__name__ == ‘__main__‘“是True,但是我們如果從另外一個.py檔案通過import匯入該檔案的時候,這時__name__的值就是我們這個py檔案的名字,而不是__main__。
這個功能還有一個用處:調試代碼的時候,在”if __name__ == ‘__main__‘“中加入一些我們的調試代碼,我們可以讓外部模組調用的時候不執行我們的調試代碼,但是如果我們想排查問題的時候,直接執行該模組檔案,調試代碼能夠正常運行!
logger.pydef logging(): print(‘ok‘)mian.pyfrom core import loggerdef main(): logger.logging()# print(__name__)if __name__ == ‘__main__‘: main()bin.pyimport os,sysbase_dir=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 添加ATM的絕對路徑# print(base_dir)sys.path.append(base_dir) # 把路徑添加到系統內容變數裡去from core import mainmain.main()
例子
現象:
1、當執行 bin.py 的時候會顯示 ok,正常運行,單獨執行 main.py 正常顯示一個 ok
2、當 main.py 注釋 if __name__ == ‘__main__‘,執行 bin.py 會顯示兩個 ok,單獨執行 main.py 正常顯示一個 ok
3、當 main.py 只有 print(__name__),執行 bin.py 只顯示 main,執行 main.py 顯示 __main__
結論:
1:if __name__ == ‘__main__‘ 是用來調試用的,在別的地方調用該模組執行的使用不會執行被調用模組下的 if __name__ == ‘__main__‘ 下的代碼
2:在被調用模組下執行程式,會執行 if __name__ == ‘__main__‘ 下的代碼,因為是自己的地方,方便調試
5、包的2種調用方式
logger.py 檔案內容
def logger(): print(‘logger‘)
# from web.web2 import logger # 二層目錄
調用 logger 模組裡的 logger方法
logger.logger()
# from web.web2.logger import logger # 調用 web包下的 web2包下的logger 模組的 logger 方法,直接用 Logger()
直接調用 logger 模組裡的 logger方法
logger()
.
Python之模組與包(下)