最近在看__main__
的官方文檔 —— https://docs.python.org/3/library/__main__.html#module-__main__,提到一個python -m
的用法,非常不理解,因此查找了不少文檔,並進行了以下總結。
$ 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
後綴。html
首先直觀的觀察執行結果,Python 的版本是 3.6.3。
編寫 script.py
腳本,內容以下:python
import sys print(sys.path) print(sys.modules)
直接執行腳本app
$ python script.py ['/home/ossifrage/workspaces/python-m', '/usr/lib/python36.zip', '/usr/lib/python3.6', ...] {..., '__main__': <module '__main__' from 'script.py'>, ...}
當作模塊方式執行spa
$ 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'>}
顯示的內容還有不少,只突出顯示出了不一樣的地方。命令行
經過比較不一樣的地方,咱們發現:code
第一種方法——直接運行腳本,當前腳本所在的路徑會加入到 sys.path
列表中,可是 sys.modules
字典中的 __main__
的路徑不是絕對路徑,只是腳本名稱。htm
第二種方法——當作模塊方式運行,當前腳本所在的路徑不會加入到 sys.path
列表中,可是 sys.modules
字典中的 __main__
的路徑是絕對路徑,同時,還引入了 runpy
和 pkgutil
兩個模塊。blog
runpy 的用途:定位並執行該模塊。主要用途在於實現命令行 -m
執行 python 模塊的效果。ip
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 命名空間。