Python之模塊與包(下)
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.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) 包所包含的文件內容文件內容
from . import api # 告訴調用 glance 包的模塊,找api 的話從你自己的 sys.path 下 glance 下開始找 apiglance包 __init__ 的文件內容
# print(‘from api init.py‘) # __all__=[‘x‘,‘y‘,‘policy‘] # all 方法對應 # x=1 # y=2 from . 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 glance glance.api.policy.get() # 如果是導入跟“包”同級的aaa包下的 glacne,就要先找到兩者的父級目錄,再從父級目錄開始找 import os import sys base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) print(base_dir) # 父級目錄 sys.path.append(base_dir) from aaa.glance.api import policy policy.get()跟 glance 同級的文件 test.py
例2:
if __name__==‘__main__‘: # 表示把自己當做腳本去用 print(‘ok‘)
如果我們是直接執行某個.py文件的時候,該文件中那麽”__name__ == ‘__main__‘“是True,但是我們如果從另外一個.py文件通過import導入該文件的時候,這時__name__的值就是我們這個py文件的名字,而不是__main__。
這個功能還有一個用處:調試代碼的時候,在”if __name__ == ‘__main__‘“中加入一些我們的調試代碼,我們可以讓外部模塊調用的時候不執行我們的調試代碼,但是如果我們想排查問題的時候,直接執行該模塊文件,調試代碼能夠正常運行!
logger.py def logging(): print(‘ok‘) mian.py from core import logger def main(): logger.logging() # print(__name__) if __name__ == ‘__main__‘: main() bin.py import os,sys base_dir=os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 添加ATM的絕對路徑 # print(base_dir) sys.path.append(base_dir) # 把路徑添加到系統環境變量裏去 from core import main main.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之模塊與包(下)