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



13 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__"

if __name__ '__main__' python

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__'__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__是一個全局變量(在Python中,全局實際上意味著在模塊級別上 ),它存在於所有名稱空間中。 它通常是模塊的名稱(作為str類型)。

然而,作為唯一的特殊情況,無論你在哪個Python進程中運行,如在mycode.py中:

python mycode.py

否則,匿名全局命名空間將為其__name__分配值'__main__'

因此,包括最後一行

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

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

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

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



當我們的模塊( M.py )中存在某些語句時,我們希望在它作為main(未導入)運行時執行,我們可以將這些語句(測試用例,打印語句)放在這個if塊下。

默認情況下(當模塊作為main運行,而不是導入時) __name__變量設置為"__main__" ,當它被導入時, __name__變量將獲得不同的值,很可能是模塊的名稱( 'M' )。 這有助於將模塊的不同變體一起運行,並將它們的特定輸入和輸出語句分開,以及是否存在任何測試用例。

簡而言之 ,使用這個' if __name__ == "main" '塊來防止(某些)代碼在導入模塊時運行。




簡而言之, __name__是為每個腳本定義的變量,用於定義腳本是作為主模塊運行還是作為導入模塊運行。

所以,如果我們有兩個腳本;

#script1.py
print "Script 1's name: {}".format(__name__)

#script2.py
import script1
print "Script 2's name: {}".format(__name__)

執行script1的輸出是

Script 1's name: __main__

執行script2的輸出是:

Script1's name is script1
Script 2's name: __main__

如您所見, __name__告訴我們哪個代碼是'main'模塊。 這很好,因為你可以只編寫代碼而不必擔心C / C ++中的結構問題,如果文件沒有實現'main'函數那麼它就不能編譯為可執行文件,如果是,它不能用作庫。

假設您編寫了一個Python腳本,它可以執行一些非常棒的操作,並且可以實現一系列對其他用途有用的函數。 如果我想使用它們,我只需導入你的腳本並使用它們而不執行你的程序(假設你的代碼只在if __name__ == "__main__": context中執行)。 而在C / C ++中,您必須將這些部分分成一個單獨的模塊,然後包含該文件。 想像下面的情況;

箭頭是導入鏈接。 對於每個試圖包含前面的模塊代碼的三個模塊,有六個文件(九個,計算實現文件)和五個鏈接。 這使得很難將其他代碼包含到C項目中,除非它專門編譯為庫。 現在想像一下Python:

您編寫了一個模塊,如果有人想要使用您的代碼,他們只需導入它, __name__變量可以幫助將程序的可執行部分與庫部分分開。




考慮:

if __name__ == "__main__":
    main()

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

但是,如果模塊使用Python腳本,則會執行if語句之外的任何代碼,因此if \__name__ == "\__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 ”。

希望這會有所幫助。




從命令行調用Python文件時,這是一個特殊的功能。 這通常用於調用“main()”函數或執行其他適當的啟動代碼,例如命令行參數處理。

它可以用幾種方式編寫。 另一個是:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

我並不是說你應該在生產代碼中使用它,但它可以說明if __name__ == '__main__'沒有任何“神奇”。 在Python文件中調用main函數是一個很好的約定。




的原因

if __name__ == "__main__":
    main()

主要是為了避免因直接導入代碼而導致的導入鎖定問題。 如果直接調用文件(即__name__ == "__main__"情況),則希望main()運行,但如果導入了代碼,則導入器必須從真正的主模塊輸入代碼以避免導入鎖定問題。

副作用是您自動登錄支持多個入口點的方法。 您可以使用main()作為入口點來運行程序, 但您不必這樣做 。 雖然setup.py需要main() ,但其他工具使用備用入口點。 例如,要將文件作為gunicorn進程運行,請定義app()函數而不是main() 。 與setup.pygunicorn導入您的代碼,因此您不希望它在導入時執行任何操作(因為導入鎖定問題)。




考慮:

print __name__

上面的輸出是__main__

if __name == "__main__":
  print "direct method"

以上陳述是正確的,並打印“直接方法” 。 假設他們在其他類中導入了這個類,它不會打印“直接方法”,因為在導入時,它會將__name__ equal to "firstmodel name"設置__name__ equal to "firstmodel name"




如果此.py文件由其他.py文件導入,則不會執行“if語句”下的代碼。

如果此.py由python this_py.pyshell下運行,或在Windows中雙擊。“if語句”下的代碼將被執行。

它通常是為測試而編寫的。




所有答案都解釋了功能。但我將提供一個使用它的例子,這可能有助於進一步清除這個概念。

假設您有兩個Python文件,a.py和b.py. 現在,a.py導入b.py. 我們運行a.py文件,首先執行“import b.py”代碼。在運行其餘的a.py代碼之前,文件b.py中的代碼必須完全運行。

在b.py代碼中,有一些代碼對該文件b.py是獨占的,我們不希望任何導入b.py文件的其他文件(b.py文件除外)運行它。

這就是這行代碼檢查的內容。如果它是運行代碼的主文件(即b.py),在這種情況下它不是(a.py是運行的主文件),那麼只有代碼被執行。




如果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__



Related