查看 Python 的 help 內容
$ python --help
...
-m mod : run library module as a script (terminates option list)
# 直譯就是按照腳本的方式執行模塊
...
有無 -m 參數的比較
1. python script.py # 直接執行腳本
2. python -m script.py # 當做模塊的方式執行,相當於 import
一般情況下,我們會想當然的認爲,有無參數 -m 對程序會有不同的影響,但是很可惜,第二種寫法是會在程序執行之後報錯的。其正確的寫法是:丟掉 .py 後綴。
首先直觀的觀察執行結果,Python 的版本是 3.6.3。
編寫 script.py 腳本,內容如下:
import sys
print(sys.path)
print(sys.modules)
直接執行腳本
$ python script.py
['/home/ossifrage/workspaces/python-m', '/usr/lib/python36.zip', '/usr/lib/python3.6', ...]
{..., '__main__': <module '__main__' from 'script.py'>, ...}
當做模塊方式執行
$ python -m script
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', ...]
{..., '__main__': <module 'run' from '/home/ossifrage/workspaces/python-m/script.py'>, ..., 'runpy': <module 'runpy' from '/usr/lib/python3.6/runpy.py'>, 'pkgutil': <module 'pkgutil' from '/usr/lib/python3.6/pkgutil.py'>}
顯示的內容還有很多,只突出顯示出了不同的地方。
通過比較不同的地方,我們發現:
第一種方法——直接運行腳本,當前腳本所在的路徑會加入到 sys.path 列表中,但是 sys.modules
字典中的 __main__
的路徑不是絕對路徑,只是腳本名稱。
第二種方法——當做模塊方式運行,當前腳本所在的路徑不會加入到 sys.path
列表中,但是 sys.modules
字典中的 __main__
的路徑是絕對路徑,同時,還引入了 runpy
和 pkgutil
兩個模塊。
runpy 的用途:定位並執行該模塊。主要用途在於實現命令行 -m 執行 python 模塊的效果。
pkgutil 的用途:獲取包裏面的所有模塊列表。pkgutil.get_data()
可讀取包內任何文件內容。
模塊的導入機制
其實,上面的內容涉及到了 Python 包模塊的導入機制。
要理解模塊的導入機制,得理解幾個關鍵的名詞。sys.path -> sys.modules -> < module >.__dict__。
sys.path:是一個列表。保存着模塊的搜索路徑。如果路徑沒有存在與該列表中,可使用 sys.path.append()
導入。
sys.modules: 是一個字典。所有加載到內存中的模塊都存放在該字典中。當 import 一個模塊的時候,首先會在這個字典中查找是否已經加載了目標模塊。如果已加載,則將模塊的名字加入到正在調用 import 的模塊的 Local 命名空間(也就是< module >.__dict__
)中。如果沒有,則從 sys.path
查找,找到後載入內存,並加入到 sys.modules
字典,名稱也將導入到當前模塊的 Local 命名空間。