__name__ == '__main__' 到底是什麼意思

ARM的程式設計師敲著詩歌的夢發表於2019-02-12

__name__ == '__main__'到底是什麼意思

相信許多人初學 Python 時,常會在例子程式中看到如下語句:

if __name__ == '__main__':
    foo()  # 或其他語句

第 1 行的__name__ == '__main__'到底是什麼意思呢?

首先,如果你永遠都只執行一個 xxx.py,而不去 import它的話,那你完全不需要了解這是什麼。例如你寫了一個程式,檔名叫 hello.py

print("====this is hello.py====")
def foo():
    print("hello")
print("call foo() which is defined here") 
foo()
print("====this is hello.py END ====")

然後你總是直接執行它,就像這樣

$ python3 hello.py 
====this is hello.py====
call foo() which is defined here
hello
====this is hello.py END ====

這完全沒有問題。

但是,當別人想引用你的foo()函式時,就有問題了。

例如別人寫了一個檔案,名字是 world.py

# world.py
print("====this is world.py====")
from hello import foo

print("call foo() which is defined in other file")
foo()
print("====this is world.py END ====")

執行結果如下:

$ python3 world.py 
====this is world.py====
====this is hello.py====
call foo() which is defined here
hello
====this is hello.py END ====
call foo() which is defined in other file
hello
====this is world.py END ====

可以看到,直譯器是逐行解釋原始碼的,當執行到原始碼的第 3 行時,也就是 hello.py 被引用時,hello.py 的每一行都會被直譯器讀取並執行,執行效果就是結果中的3~6行,然後直譯器執行原始碼的5~7行。

如果你不想要結果中的3~6行,該怎麼做呢?

Python 直譯器執行程式碼時,有一些內建、隱含的變數,__name__就是其中之一,其意義是“模組名稱”。

如果該模組是被引用,那麼__name__的值會是此模組的名稱;如果該模組是直接被執行,那麼__name__的值是__main__

或許你還不明白,那我們來做個實驗。

# hello.py
print("====this is hello.py====")
print(__name__)
def foo():
    print("Ha")
print("call foo() which is defined here") 
foo()
print("====this is hello.py END ====")

請注意上面第3行

# world.py
print("====this is world.py====")
print(__name__)
from hello import foo
print("call foo() which is defined in other file")
foo()
print("====this is world.py END ====")

同樣,請注意上面第3行

我們看一下執行結果。

對於第一個:

$ python3 hello.py 
====this is hello.py====
__main__
call foo() which is defined here
Ha
====this is hello.py END ====

從結果的第3行可以看出,對於直接執行的模組,其模組名是 __main__

對於第二個:

$ python3 world.py
====this is world.py====
__main__    # 因為 world.py 被直接執行,所以這裡的值是 __main__
====this is hello.py====
hello       # 因為 hello.py 被引用,所以這裡的值是 hello
call foo() which is defined here
Ha
====this is hello.py END ====
call foo() which is defined in other file
Ha
====this is world.py END ====

注意到第5行了嗎?這裡的“hello”正是 hello.py 被引用時的模組名稱。

由此可見,__name__的值在模組被直接執行時與被引用時是不同的。

回到上面的問題:當一個模組被引用時,如何不執行該模組的語句?答案就是靠判斷__name__是否等於 __main__。當一個模組被直接執行時,其__name__必然等於__main__;當一個模組被引用時,其__name__必然等於檔名(不含.py);

總結

之所以常看見這樣的寫法,是因為該程式可能有“單獨執行”(例如執行一些單元測試)與“被引用”兩種情況,鑑於這兩種情況中__name__的值是不同的:當一個模組被直接執行時,其__name__必然等於__main__;當一個模組被引用時,其__name__必然等於檔名(不含.py)。所以利用判斷__name__ == '__main__'的真假就可以將這兩種情況區分出來。

參考資料

http://blog.castman.net/教學/2018/01/27/python-name-main.html

相關文章