最近在看
__main__
的官方文件 —— https://docs.python.org/3/library/__main__.html#module-__main__,提到一個python -m
的用法,很是不理解,所以查詢了很多文件,並進行了如下總結。
檢視 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 名稱空間。
reference
- [[python]自問自答:python -m引數?](https://www.cnblogs.com/xuewe…
- Python的-m引數
- python中的import(涉及pkgutil和inspect包)
- import 迷宮