bandclass
├── __init__.py
├── __main__.py
└── student.py
當使用 -m
旗標 (flag) 直接從命令列呼叫套件本身時,將執行 __main__.py
。例如:
$ python -m bandclass
該命令將導致 __main__.py
執行。如何利用此機制將取決於你正在編寫的套件的性質,但在這種虛構的情況下,允許教師搜尋學生可能是有意義的:
# bandclass/__main__.py
import sys
from .student import search_students
student_name = sys.argv[1] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')
請注意,from .student import search_students
是相對引入的範例。在引用套件內的模組時,可以使用此引入樣式。有關更多詳細資訊,請參閱 模組 (Module) 教學章節中的 套件內引用。
慣用 (Idiomatic) 用法
__main__.py
的內容通常不會被 if __name__ == '__main__'
區塊包圍。相反的,這些檔案保持簡短並引入其他模組的函式來執行。那些其他模組就可以輕鬆地進行單元測試並且可以正確地重複使用。
如果在套件裡面的 __main__.py
檔案使用 if __name__ == '__main__'
區塊,它依然會如預期般地運作。因為當引入套件,其 __name__
屬性將會包含套件的路徑:
>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'
但這對於 .zip
檔案根目錄中的 __main__.py
檔案不起作用。因此,為了保持一致性,最小的、沒有 __name__
檢查的 __main__.py
會是首選。
請參閱 venv
作為標準函式庫中具有最小 __main__.py
的套件為範例。它不包含 if __name__ == '__main__'
區塊。你可以使用 python -m venv [directory]
來呼叫它。
請參閱 runpy
取得有關直譯器可執行檔的 -m
旗標的更多詳細資訊。
請參閱 zipapp
了解如何執行打包成 .zip 檔案的應用程式。在這種情況下,Python 會在封存檔案的根目錄中尋找 __main__.py
檔案。
import __main__
無論 Python 程式是從哪個模組啟動的,在同一程式中執行的其他模組都可以透過匯入 __main__
模組來引入頂層環境的作用域 (namespace)。這不會引入 __main__.py
檔案,而是引入接收特殊名稱 '__main__'
的模組。
這是一個使用 __main__
命名空間的範例模組:
# namely.py
import __main__
def did_user_define_their_name():
return 'my_name' in dir(__main__)
def print_user_name():
if not did_user_define_their_name():
raise ValueError('Define the variable `my_name`!')
if '__file__' in dir(__main__):
print(__main__.my_name, "found in file", __main__.__file__)
else:
print(__main__.my_name)
該模組的範例用法如下:
# start.py
import sys
from namely import print_user_name
# my_name = "Dinsdale"
def main():
try:
print_user_name()
except ValueError as ve:
return str(ve)
if __name__ == "__main__":
sys.exit(main())
現在,如果我們啟動程式,結果將如下所示:
$ python start.py
Define the variable `my_name`!
程式的結束代碼將為 1,表示出現錯誤。取消註解 my_name = "Dinsdale"
而修復程式後,現在它以狀態碼 0 結束,表示成功:
$ python start.py
Dinsdale found in file /path/to/start.py
請注意,引入 __main__
並不會因為不經意地執行放在 start
模組中 if __name__ == "__main__"
區塊的頂層程式碼(本來是給腳本使用的)而造成任何問題。為什麼這樣做會如預期運作?
當 Python 直譯器啟動時,會在 sys.modules
中插入一個空的 __main__
模組,並透過執行頂層程式碼來填充它。在我們的範例中,這是 start
模組,它將逐行執行並引入 namely
。接著,namely
引入 __main__
(其實是 start
)。這就是一個引入循環!幸運的是,由於部分填充的 __main__
模組存在於 sys.modules
中,Python 將其傳遞給 namely
。請參閱引入系統參考文件中的關於 __main__ 的特別考量了解其工作原理的詳細資訊。
Python REPL 是「頂層環境」的另一個範例,因此 REPL 中定義的任何內容都成為 作域的一部分:
>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
>>> namely.print_user_name()
Jabberwocky
請注意,在這種情況下, __main__
作用域不包含 __file__
屬性,因為它是互動式的。
__main__
作用域用於 pdb
和 rlcompleter
的實作。
2001-2025, Python Software Foundation.
This page is licensed under the Python Software Foundation License Version 2.
Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
See History and License for more information.