1. 程式人生 > >Python之模塊與包(下)

Python之模塊與包(下)

dir 模塊 關於 mode 二層 man manage 組織 否則

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、關於包相關的導入語句也分為importfrom ... import ...兩種,但是無論哪種,無論在什麽位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,否則非法。可以帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。但對於導入後,在使用時就沒有這種限制了,點的左邊可以是包,模塊,函數,類(它們都可以用點的方式調用自己的屬性)。

例:import spam.x

導入前:import spam.x:如果 spam 是一個模塊,就會報錯,spam 必須是一個包

導入後:spam.x 直接調用模塊 spam 下的 x 屬性

#2import導入文件時,產生名稱空間中的名字來源於文件,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 下開始找 api
glance包 __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之模塊與包(下)