[python] 如果__name__ ==“__main__”:做什麼?



Answers

通過將腳本作為命令傳遞給Python解釋器來運行腳本時,

python myscript.py

所有處於縮進級別0的代碼都會被執行。 定義的函數和類已經定義好了,但是沒有任何代碼可以運行。 與其他語言不同,沒有main()函數可以自動運行 - main()函數隱含在頂層的所有代碼。

在這種情況下,頂級代碼是一個if塊。 __name__是一個內置變量,用於計算當前模塊的名稱。 但是,如果模塊正在直接運行(如上面的myscript.py ),則__name__被設置為字符串"__main__" 。 因此,您可以測試您的腳本是直接運行還是通過測試進行其他操作

if __name__ == "__main__":
    ...

如果你的腳本被導入到另一個模塊中,它的各種函數和類定義將被導入,並且它的頂級代碼將被執行,但是if子句的then-body中的代碼將不會作為條件運行沒有得到滿足。 作為基本示例,請考慮以下兩個腳本:

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

現在,如果你調用解釋器

python one.py

輸出將是

top-level in one.py
one.py is being run directly

如果您運行two.py改為:

python two.py

你得到

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

因此,當模塊one被加載時,其__name__等於"one"而不是"__main__"

Question

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))



if __name__ == "__main__":做什麼?

__name__是一個全局變量(在Python中,全局實際上是指模塊級別 ),它存在於所有名稱空間中。 它通常是模塊的名稱(作為str類型)。

然而,作為唯一的特例,在任何你運行的Python進程中,就像在mycode.py中一樣:

python mycode.py

否則匿名全局命名空間被賦值為'__main__'給它的__name__

因此,包括最後一行

if __name__ == '__main__':
    main()
  • 在mycode.py腳本的末尾,
  • 當它是由Python進程運行的主要入口點模塊時,

將導致腳本的唯一定義的main函數運行。

使用此構造的另一個好處是:您還可以將代碼作為另一個腳本中的模塊導入,然後在程序決定時並運行主函數:

import mycode
# ... any amount of other code
mycode.main()



系統(Python解釋器)為源文件(模塊)提供了許多變量。 你可以隨時獲得它們的值,所以,讓我們專注於__name__變量/屬性:

當Python加載源代碼文件時,它會執行其中的所有代碼。 (請注意,它不調用文件中定義的所有方法和函數,但它確實定義了它們。)

儘管在解釋器執行源代碼文件之前,它為該文件定義了一些特殊變量; __name__是Python自動為每個源代碼文件定義的特殊變量之一。

如果Python將這個源代碼文件作為主程序(即您運行的文件)加載,那麼它會為該文件設置一個特殊的__name__變量以獲得值“__main__”

如果這是從另一個模塊導入的, __name__將被設置為該模塊的名稱。

所以,在你的例子中:

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))

意味著代碼塊:

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

只有在您直接運行模塊時才會執行; 如果另一個模塊正在調用/導入它,代碼塊將不會執行,因為__name__的值在該特定實例中不等於“ main ”。

希望這有助於。




如果name ==' main ':

我們經常看到__name__ == '__main__'

它檢查是否正在導入模塊。

換句話說,只有當代碼直接運行時, if塊中的代碼才會被執行。 這裡directly意味著not imported

讓我們看看它使用一個簡單的代碼打印模塊的名稱:

# test.py
def test():
   print('test module name=%s' %(__name__))

if __name__ == '__main__':
   print('call test()')
   test()

如果我們通過python test.py直接運行代碼,模塊名稱是__main__

call test()
test module name=__main__



if __name__ == "__main__":做什麼?

概述基本知識:

  • 作為程序入口點的模塊中的全局變量__name__'__main__' 。 否則,它是您通過導入模塊的名稱。

  • 因此,如果模塊是程序的入口點, if塊下的代碼才會運行。

  • 它允許模塊中的代碼可被其他模塊導入,而無需在導入時執行下面的代碼塊。

我們為什麼需要這個?

開發和測試你的代碼

假設您正在編寫一個旨在用作模塊的Python腳本:

def do_important():
    """This function does something very important"""

可以通過將該函數的這個調用添加到底部測試該模塊:

do_important()

並運行它(在命令提示符下),如下所示:

~$ python important.py

問題

但是,如果您想將模塊導入到另一個腳本中:

import important

在導入時,將調用do_important函數,因此您可能會在底部註釋掉函數調用do_important()

# do_important() # I must remember to uncomment to execute this!

然後你必須記住你是否註釋掉了你的測試函數調用。 而這種額外的複雜性意味著你可能會忘記,使你的開發過程更麻煩。

更好的方法

__name__變量指向Python解釋器恰好在此刻的任何地方的名稱空間。

在導入的模塊中,它是該模塊的名稱。

但是在主模塊(或交互式Python會話,即解釋器的Read,Eval,Print Loop或REPL)中,您正在運行"__main__"

所以如果你在執行前檢查:

if __name__ == "__main__":
    do_important()

通過以上所述,只有當您將代碼作為主模塊運行時(或者有意從另一個腳本調用它),代碼才會執行。

更好的方式

不過,有一種Pythonic方法可以改善這一點。

如果我們想從模塊外部運行這個業務流程呢?

如果我們在我們開發和測試類似這樣的函數時將代碼放入代碼中,然後在執行以下操作後立即檢查'__main__'

def main():
    """business logic for when running this module as the primary one!"""
    setup()
    foo = do_important()
    bar = do_even_more_important(foo)
    for baz in bar:
        do_super_important(baz)
    teardown()

# Here's our payoff idiom!
if __name__ == '__main__':
    main()

如果我們將模塊作為主模塊運行,我們現在有一個最終的功能用於模塊的結束。

它將允許將模塊及其函數和類導入到其他腳本中,而無需運行main函數,並且還允許在從不同的'__main__'模塊運行時調用模塊(及其函數和類),即

import important
important.main()

這個習慣用法也可以在Python文檔中找到__main__模塊的解釋。 該文指出:

該模塊代表解釋器主程序執行的(否則匿名)範圍 - 可以從標準輸入,腳本文件或交互式提示中讀取命令。 正是這種慣用的“條件腳本”節引起腳本運行的環境:

if __name__ == '__main__':
    main()



在解釋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腳本運行的東西,它將返回文件的名稱它來自哪裡。

實踐:

作為變量意味著它的值可以被覆蓋(“can”並不意味著“should”),覆蓋__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給定的值為真,則if將是包含該代碼塊的流控制語句。 我們已經看到__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

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

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




關於代碼的機制,“如何”有很多不同之處,但對我而言,直到我理解“為什麼”之前,沒有任何意義。 這應該對新程序員特別有用。

取文件“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.py ,你會import ab 。 import語句在導入時立即運行模塊,所以ab的操作在xy的剩餘部分之前被執行。 一旦完成了ab ,它繼續xy

解釋器通過__name__跟踪哪些腳本正在運行。 當你運行一個腳本時 - 無論你命名了什麼 - 解釋器將其稱為"__main__" ,使其成為運行外部腳本後返回的主或“主”腳本。 從這個"__main__"腳本調用的任何其他腳本都將其文件名指定為__name__ (例如, __name__ == "ab.py" )。 因此, if __name__ == "__main__":是解釋器的測試,以確定它是解釋/解析最初執行的'home'腳本,還是暫時窺探另一個(外部)腳本。 這使得程序員可以靈活地讓腳本直接執行而不是外部調用。

讓我們逐步了解上述代碼,了解發生了什麼,首先關注不顯示的行和它們在腳本中出現的順序。 記住函數 - 或者def - 塊在被調用之前不會自己做任何事情。 口譯員如果自言自語,可能會說些什麼:

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

最下面兩行意思是:“如果這是main或'home'腳本,則執行名為main()的函數”。 這就是為什麼你會看到def main(): block up top,它包含腳本功能的主要流程。

為什麼執行這個?

請記住我之前所說的關於進口報表的內容 當您導入一個模塊時,它不會“識別”它並等待進一步的指示 - 它實際上運行腳本中包含的所有可執行操作。 因此,將腳本中的內容放入main()函數中會有效隔離它,並將其隔離,以便在其他腳本導入時不會立即運行。

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

但是代碼沒有它

恩,那就對了。 這些單獨的函數可以從不包含在main()函數中的內聯腳本調用。 如果您習慣於(像我一樣,在編程的早期學習階段)來構建完全符合您需要的內聯腳本,並且如果您再次需要該操作,您將嘗試再次弄清楚它。 。好吧,你不習慣這種內部結構來編寫代碼,因為編譯起來比較複雜,閱讀起來不太直觀。 但是這是一個腳本,可能無法在外部調用它的函數,因為如果它做了,它會立即開始計算和分配變量。 如果你試圖重新使用一個函數,那麼很可能你的新腳本與舊腳本的關係足夠緊密,以至於會存在衝突的變量。

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

[另外, 這個線程包含@kindall的一個答案,最終幫助我理解 - 為什麼,而不是如何。 不幸的是,它被標記為這一個的重複,我認為這是一個錯誤。]




您可以將該文件作為腳本以及可導入的模塊使用

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




當你交互地運行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__":基本上是頂級腳本環境,則它指定解釋器('我具有最高優先級首先執行')。

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

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



if __name__ == "__main__":
    main()

檢查python腳本的__name__屬性是否為"__main__" 。 換句話說,如果程序本身被執行,屬性將是__main__ ,所以程序將被執行(在這種情況下是main()函數)。

但是,如果你的python腳本被模塊使用, if語句之外的任何代碼都會被執行,所以if \__name__ == "\__main__"被用來檢查程序是否被用作模塊,並且因此決定是否運行代碼。




Related