python __main__用法 '__main__' - 如果__name__ ==“__ main__”:怎麼辦?




14 Answers

當Python解釋器讀取源文件時,它會執行其中的所有代碼。

在執行代碼之前,它將定義一些特殊變量。 例如,如果Python解釋器將該模塊(源文件)作為主程序運行,則它將特殊的__name__變量設置為具有值"__main__" 。 如果從另一個模塊導入此文件,則__name__將設置為模塊的名稱。

在你的腳本的情況下,讓我們假設它作為主要功能執行,例如你說的話

python threading_example.py

在命令行上。 設置特殊變量後,它將執行import語句並加載這些模塊。 然後它將評估def塊,創建一個函數對象並創建一個名為myfunction的變量,該變量指向函數對象。 然後它將讀取if語句並看到__name__等於"__main__" ,因此它將執行那裡顯示的塊。

這樣做的一個原因是有時你會編寫一個模塊( .py文件)來直接執行它。 或者,它也可以導入並在另一個模塊中使用。 通過執行主檢查,您可以僅在希望將模塊作為程序運行時執行該代碼,而在有人只想導入模塊並自行調用函數時不執行該代碼。

有關其他詳細信息,請參閱此頁面

注意 (由Stainsor提供):如果將代碼放在函數定義之前,它將在main之前執行。

print("This code executes before main.") 

def functionA():
    print("Function A")

def functionB():
    print("Function B")

if __name__ == '__main__':
    functionA()
    functionB()

如果此模塊確實是主模塊,則此代碼會導致:

This code executes before main. 
Function A 
Function B

如果這個模塊不是主要的,你得到:

This code executes before main. 
__main__意思 '__main__'用法

if __name__ == "__main__":是什麼意思?

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

if __name__ == "__main__":
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))



__name__變量(imho)的最簡單解釋如下:

創建以下文件。

# a.py
import b

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

運行它們會得到這個輸出:

$ python a.py
Hello World from b!

如您所見,在導入模塊時,Python會將此模塊中的globals()['__name__']設置為模塊的名稱。

$ python b.py
Hello World from __main__!
Hello World again from __main__!

如您所見,在執行文件時,Python將此文件中的globals()['__name__']"__main__"




if __name__ == "__main__"是使用python myscript.py類的命令從命令行運行腳本時運行的部分。




這裡有很多不同的關於代碼的機制,“如何”,但對我來說,除非我理解“為什麼”,否則它們都沒有意義。 這應該對新程序員特別有用。

取文件“ab.py”:

def a():
    print('A function in ab file');
a()

第二個文件“xy.py”:

import ab
def main():
    print('main function: this is where the action is')
def x():
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

這段代碼到底在做什麼?

執行xy.pyimport ab 。 import語句在導入時立即運行模塊,因此ab的操作在xy的剩餘部分之前執行。 完成ab ,繼續使用xy

解釋器使用__name__跟踪正在運行的腳本。 當您運行腳本時 - 無論您將其命名為什麼 - 解釋器將其稱為"__main__" ,使其成為運行外部腳本後返回的主或“主”腳本。

從此"__main__"腳本調用的任何其他腳本都將其文件名指定為其__name__ (例如, __name__ == "ab.py" )。 因此, if __name__ == "__main__":是解釋器的測試,用於確定它是否正在解釋/解析最初執行的“home”腳本,或者它是否暫時窺視另一個(外部)腳本。 這為程序員提供了靈活性,使腳本的行為不同,如果它直接執行而不是外部調用。

讓我們逐步完成上面的代碼來了解發生了什麼,首先關注的是未縮進的行以及它們在腳本中出現的順序。 請記住,函數 - 或def - 塊在它們被調用之前不會自行執行任何操作。 如果嘟to自己,翻譯可能會說些什麼:

  • 打開xy.py作為“主頁”文件; 在__name__變量中將其__name__"__main__"
  • 使用__name__ == "ab.py"導入並打開文件。
  • 哦,一個功能。 我會記得的。
  • 好的,功能a() ; 我剛學會了這個。 打印' ab文件中函數 '。
  • 文件結束; 回到"__main__"
  • 哦,一個功能。 我會記得的。
  • 另一個。
  • 函數x() ; 好的,打印' 外圍任務:可能在其他項目中很有用 '。
  • 這是什麼? 一個if語句。 好吧,條件已經滿足(變量__name__已設置為"__main__" ),所以我將進入main()函數並打印' main函數:這就是動作的位置 '。

底部兩行表示:“如果這是"__main__"或”home“腳本,則執行名為main()的函數”。 這就是為什麼你會看到一個def main(): block up top,它包含了腳本功能的主要流程。

為什麼實現這個?

還記得我之前說的關於import語句的內容嗎? 導入模塊時,它不僅“識別”它並等待進一步的指令 - 它實際上運行腳本中包含的所有可執行操作。 因此,將腳本的內容放入main()函數中會有效隔離它,將其置於隔離狀態,以便在由另一個腳本導入時不會立即運行。

同樣,會有例外,但通常的做法是main()通常不會被外部調用。 所以你可能想知道另外一件事:如果我們不調用main() ,我們為什麼要調用腳本呢? 這是因為許多人使用獨立函數構建腳本,這些函數構建為獨立於文件中的其餘代碼運行。 然後它們被稱為腳本體內的其他地方。 這讓我想到了這個:

但代碼在沒有它的情況下工作

恩,那就對了。 可以從不包含在main()函數中的內聯腳本調用這些單獨的函數。 如果你已經習慣了(就像我在編程的早期學習階段一樣)構建完全符合你需要的內聯腳本,如果你再次需要這個操作,你會嘗試再次弄清楚它。好吧,你不習慣你的代碼的這種內部結構,因為它構建起來更複雜,而且閱讀不那麼直觀。

但這是一個可能無法在外部調用其函數的腳本,因為如果這樣做,它會立即開始計算和分配變量。 如果你正在嘗試重新使用某個函數,那麼你的新腳本可能與舊版本密切相關,而且會有相互矛盾的變量。

在拆分獨立函數時,您可以通過將它們調用到另一個腳本中來重用以前的工作。 例如,“example.py”可能導入“xy.py”並調用x() ,使用“xy.py”中的“x”函數。 (也許它正在大寫給定文本字符串的第三個單詞;從數字列表中創建NumPy數組並對它們進行平方;或者去除3D表面的去除。可能性是無限的。)

(順便說一句, 這個問題包含@kindall的答案,最終幫助我理解 - 為什麼,而不是如何。不幸的是,它被標記為這個的副本,我認為這是一個錯誤。)




讓我們以更抽象的方式看待答案:

假設我們在x.py中有這個代碼:

...
<Block A>
if __name__ == '__main__':
    <Block B>
...

當我們運行“x.py”時,塊A和B運行。

但是當我們運行另一個模塊時,只運行塊A(而不是B),例如“y.py”,其中導入了xy並且從那裡運行代碼(就像“x.py”中的函數是從y.py調用。




以交互方式運行Python時,將為本地__name__變量分配值__main__ 。 同樣,當您從命令行執行Python模塊,而不是將其導入另一個模塊時,會為其__name__屬性分配值__main__ ,而不是模塊的實際名稱。 通過這種方式,模塊可以查看自己的__name__值,以確定它們的使用方式,無論是作為對另一個程序的支持還是作為從命令行執行的主應用程序。 因此,以下習語在Python模塊中很常見:

if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.



在解釋if __name__ == '__main__'任何內容之前,了解__name__是什麼以及它的作用非常重要。

什麼是__name__

__name__DunderAlias - 可以被認為是一個全局變量(可以從模塊訪問),並以類似於global

它是一個字符串(全局如上所述),由type(__name__) (產生<class 'str'> type(__name__) <class 'str'> ),並且是Python 3Python 2版本的內置標準。

哪裡:

它不僅可以在腳本中使用,還可以在解釋器和模塊/包中找到。

解釋:

>>> print(__name__)
__main__
>>>

腳本:

test_file.py

print(__name__)

導致__main__

模塊或包裝:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

導致somefile

請注意,在包或模塊中使用時, __name__將獲取文件的名稱。 沒有給出實際模塊或包路徑的路徑,但是它有自己的DunderAlias __file__ ,允許這樣做。

您應該看到, __name__ ,其中主文件(或程序)將始終返回__main__ ,如果它是模塊/包,或者其他任何Python腳本運行,將返回文件的名稱它起源於哪裡。

實踐:

作為變量意味著它的值可以被覆蓋(“可以”並不意味著“應該”),覆蓋__name__的值將導致缺乏可讀性。 所以不要出於任何原因這樣做。 如果需要變量定義新變量。

始終假定__name__的值為__main__或文件名。 再次更改此默認值將導致更多的混淆,它將做好,導致進一步的問題。

例:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

一般認為在腳本中包含if __name__ == '__main__'是一種好習慣。

現在回答if __name__ == '__main__'

現在我們知道__name__的行為變得更加清晰:

if是一個流控制語句,如果給定的值為true,則包含將執行的代碼塊。 我們已經看到__name__可以使用__main__或從中導入的文件名。

這意味著如果__name__等於__main__那麼該文件必須是主文件,並且必須實際運行(或者它是解釋器),而不是導入到腳本中的模塊或包。

如果確實__name__確實取了__main__的值,那麼該代碼塊中的任何內容都將執行。

這告訴我們如果運行的文件是主文件(或者您直接從解釋器運行),那麼必須執行該條件。 如果它是一個包,那麼它不應該,並且該值不會是__main__

模塊:

__name__也可以在模塊中用於定義模塊的名稱

變種:

使用__name__也可以做其他不太常見但有用的事情,我將在這裡展示一些:

僅在文件是模塊或包時執行:

if __name__ != '__main__':
    # Do some useful things 

如果文件是主文件,則運行一個條件,如果不是,則運行另一個條件:

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

您還可以使用它在包和模塊上提供可運行的幫助功能/實用程序,而無需精心使用庫。

它還允許模塊作為主腳本從命令行運行,這也非常有用。




我認為最好用深入簡單的方式打破答案:

__name__ :Python中的每個模塊都有一個名為__name__的特殊屬性。 它是一個內置變量,它返回模塊的名稱。

__main__ :與其他編程語言一樣,Python也有一個執行入口點,即main。 '__main__' 是頂級代碼執行的範圍的名稱 。 基本上,您有兩種使用Python模塊的方法:直接將其作為腳本運行,或者導入它。 當模塊作為腳本運行時,其__name__設置為__main__

因此,當模塊作為主程序運行時, __name__屬性的值設置為__main__ 。 否則, __name__的值將設置為包含模塊的名稱。




if __name__ == "__main__":基本上是頂級腳本環境,它指定解釋器('我具有最高優先級首先執行')。

'__main__'是頂級代碼執行的範圍的名稱。 從標準輸入,腳本或交互式提示中讀取時,模塊的__name__設置為'__main__'

if __name__ == "__main__":
    # Execute only if run as a script
    main()



您可以將文件用作腳本以及可導入模塊

fibo.py(一個名為fibo的模塊)

# Other modules can IMPORT this MODULE to use the function fib
def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

# This allows the file to be used as a SCRIPT
if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

參考: https://docs.python.org/3.5/tutorial/modules.htmlhttps://docs.python.org/3.5/tutorial/modules.html




在本頁的答案中,我一直在閱讀這麼多內容。 我會說,如果你知道這件事,肯定會理解那些答案,否則,你仍然感到困惑。

簡而言之,您需要了解以下幾點:

  1. import a動作實際運行所有可以在“a”中運行import a動作

  2. 由於第1點,您可能不希望在導入時在“a”中運行所有內容

  3. 要解決第2點中的問題,python允許您進行條件檢查

  4. __name__是所有.py模塊中的隱式變量; 導入__name__ ,a.py模塊的__name__值設置為文件名“a”; 當a.py直接使用“python a.py”運行時,這意味著a.py是入口點,那麼a.py模塊的__name__值設置為字符串__main__

  5. 根據python如何__name__為每個模塊設置變量的機制,你知道如何實現第3點嗎?答案很簡單,對吧?放一個if條件:if __name__ == "__main__": ...; 你可以__name__ == "a"根據你的功能需要放置

python特別重要的是第4點!其餘的只是基本邏輯。




創建一個文件,a.py

print(__name__) # It will print out __main__

__name__始終等於直接運行__main__該文件顯示這是主文件。

在同一目錄中創建另一個文件b.py

import a  # Prints a

運行。它將打印一個,即導入的文件的名稱。

因此,為了顯示同一文件的兩種不同行為,這是一個常用的技巧:

# Code to be run when imported into another python file

if __name__ == '__main__':
    # Code to be run only when run directly



這個答案適用於學習Python的Java程序員。每個Java文件通常都包含一個公共類。您可以通過兩種方式使用該類:

  1. 從其他文件中調用該類。你只需要在調用程序中導入它。

  2. 出於測試目的,單獨運行類。

對於後一種情況,該類應包含一個public static void main()方法。在Python中,此目的由全局定義的標籤提供'__main__'




最近,我在創建python(深度學習)課程時遇到了這個問題,並且根據我的理解並同意上面列出的頂級解釋,我將詳細說明

__name__=="__main__"

有時我們在.py文件中構造一個類,並在該類中定義了許多函數。但是我們不想為了一個目的而處理所有這些類函數。例如,用於創建類並定義一些用於數據創建的函數(.npy文件),而一些用於數據加載。所以,如果我們定義

__name__=="__main__"

XXX = CLASS_NAME()

xxx.create_data()

意味著如果我們調用.py文件,那麼它只會創建數據而不會處理其他類函數。其他類函數(數據加載)也可以由其他類導入。




Related