__Name__ == “__main__” ise ne yapar?


6064

Aşağıdaki kod verildiğinde ne yapar 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))

Has if __name__ == "__main__":bloğu koşulu kaldırılmıştır / Python 3 kadarıyla eskitiliyor? Bunu belirten bazı bilgiler buldum.
carloswm85

2
@ carloswm85 Bu doğru değil.
Giorgos Myrianthous

Yanıtlar:


6643

Python yorumlayıcısı bir kaynak dosyasını okuduğunda, iki şey yapar:

  • gibi birkaç özel değişken ayarlar __name__ve sonra

  • dosyada bulunan tüm kodu yürütür.

Bunun nasıl çalıştığını ve __name__Python komut dosyalarında her zaman gördüğümüz kontroller hakkındaki sorunuzla nasıl ilişkili olduğunu görelim.

Kod Örneği

İçe aktarma ve komut dosyalarının nasıl çalıştığını keşfetmek için biraz farklı bir kod örneği kullanalım. Aşağıdakilerin adlı bir dosyada olduğunu varsayalım foo.py.

# Suppose this is foo.py.

print("before import")
import math

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

print("before functionB")
def functionB():
    print("Function B {}".format(math.sqrt(100)))

print("before __name__ guard")
if __name__ == '__main__':
    functionA()
    functionB()
print("after __name__ guard")

Özel Değişkenler

Python yorumlayıcısı bir kaynak dosyasını okuduğunda, önce birkaç özel değişken tanımlar. Bu durumda, __name__değişkeni önemsiyoruz .

Modülünüz Ana Program Olduğunda

Modülünüzü (kaynak dosya) ana program olarak çalıştırıyorsanız, ör.

python foo.py

tercüman kodlanmış dize atar "__main__"için __name__değişken, yani

# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__" 

Modülünüz Başka Biri Tarafından İçe Aktarıldığında

Öte yandan, başka bir modülün ana program olduğunu ve modülünüzü içe aktardığını varsayalım. Bu, ana programda veya başka bir modülde ana programın içe aktardığı gibi bir ifade olduğu anlamına gelir:

# Suppose this is in some other main program.
import foo

Yorumlayıcı foo.pydosyanızı arayacaktır (birkaç başka varyantı da arayacaktır) ve bu modülü çalıştırmadan önce "foo", içe aktarma ifadesinden __name__değişkene ad atayacaktır;

# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"

Modül Kodunu Çalıştırma

Özel değişkenler ayarlandıktan sonra, yorumlayıcı her seferinde bir deyim olmak üzere modüldeki tüm kodu yürütür. Kod açıklaması ile yan tarafta başka bir pencere açmak isteyebilirsiniz, böylece bu açıklama ile birlikte takip edebilirsiniz.

Her zaman

  1. Dizeyi yazdırır "before import"(tırnak işaretleri olmadan).

  2. mathModülü yükler ve adlı değişkene atar math. Bu, import mathaşağıdakilerle değiştirmeye eşdeğerdir ( __import__Python'da bir dize alan ve gerçek içe aktarmayı tetikleyen düşük düzeyli bir işlev olduğunu unutmayın ):

# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
  1. Dizeyi yazdırır "before functionA".

  2. defBir fonksiyon nesnesi oluşturarak bloğu yürütür ve daha sonra bu fonksiyon nesnesini adlı bir değişkene atar functionA.

  3. Dizeyi yazdırır "before functionB".

  4. İkinci defbloğu yürütür, başka bir işlev nesnesi oluşturur ve ardından adlandırılan bir değişkene atar functionB.

  5. Dizeyi yazdırır "before __name__ guard".

Yalnızca Modül Ana Program Olduğunda

  1. Modülünüz ana programsa, o zaman __name__gerçekten ayarlanmış olduğunu "__main__"görür ve iki işlevi çağırır, dizeleri "Function A"ve yazdırır "Function B 10.0".

Yalnızca Modülünüz Başka Biri Tarafından İçe Aktarıldığında

  1. ( bunun yerine ) Modülünüz ana program değilse ancak başka bir program tarafından içe aktarılmışsa __name__, olmayacak "foo", olmayacak "__main__"ve ififadenin gövdesini atlayacaktır .

Her zaman

  1. Her "after __name__ guard"iki durumda da dizeyi yazdıracaktır .

özet

Özetle, iki durumda yazdırılacaklar şunlardır:

# What gets printed if foo is the main program
before import
before functionA
before functionB
before __name__ guard
Function A
Function B 10.0
after __name__ guard
# What gets printed if foo is imported as a regular module
before import
before functionA
before functionB
before __name__ guard
after __name__ guard

Neden Bu Şekilde Çalışıyor?

Doğal olarak neden herhangi birinin bunu isteyeceğini merak edebilirsiniz. Bazen .py, diğer programlar ve / veya modüller tarafından modül olarak kullanılabilen ve ana programın kendisi olarak da çalıştırılabilen bir dosya yazmak istersiniz . Örnekler:

  • Modülünüz bir kitaplıktır, ancak bazı birim testleri veya bir demo çalıştıran bir komut dosyası moduna sahip olmak istersiniz.

  • Modülünüz yalnızca ana program olarak kullanılır, ancak bazı birim testleri vardır ve test çerçevesi .py, komut dosyanız gibi dosyaları içe aktararak ve özel test işlevlerini çalıştırarak çalışır. Sadece modülü içe aktardığı için komut dosyasını çalıştırmayı denemek istemezsiniz.

  • Modülünüz çoğunlukla ana program olarak kullanılır, ancak ileri düzey kullanıcılar için programcı dostu bir API sağlar.

Bu örneklerin ötesinde, Python'da bir komut dosyası çalıştırmanın sadece birkaç sihirli değişken oluşturması ve komut dosyasını içe aktarması zariftir. Komut dosyasını "çalıştırmak", komut dosyasının modülünü içe aktarmanın bir yan etkisidir.

Düşünce için yiyecek

  • Soru: Birden fazla __name__kontrol bloğum olabilir mi? Cevap: Bunu yapmak garip, ama dil sizi durdurmayacak.

  • Aşağıdakilerin olduğunu varsayalım foo2.py. python foo2.pyKomut satırında söylerseniz ne olur ? Neden?

# Suppose this is foo2.py.

def functionA():
    print("a1")
    from foo2 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    functionA()
    print("m2")
print("t2")
  • Şimdi, __name__check- in'i kaldırırsanız ne olacağını öğrenin foo3.py:
# Suppose this is foo3.py.

def functionA():
    print("a1")
    from foo3 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
print("m1")
functionA()
print("m2")
print("t2")
  • Komut dosyası olarak kullanıldığında ne yapacak? Modül olarak alındığında?
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")

print("before __name__ guard")
if __name__ == "__main__":
    bar()
print("after __name__ guard")

14
Meraktan: subprocess.run('foo_bar.py')Python betiğinde çalıştırırsam ne olur ? Sanırım bu foo_bar, __name__ = '__main__'cmd'yi foo_bar.pyelle döndürdüğümde olduğu gibi başlayacak . Durum bu mu? @MrFooz 'cevabını göz önünde bulundurarak bunu yaparken ve aynı anda istediğim kadar "ana" modüle sahip olmak için herhangi bir sorun olmamalıdır. __name__Değerin değiştirilmesi veya birbirinden bağımsız olarak birkaç örnek yaratan (veya birbirini yaratan örneklerin subprocess) birbirleriyle etkileşime girmesi bile Python için her zamanki gibi olmalıdır. Bir şey mi özledim?
hajef

12
@hajef İşlerin nasıl çalışacağı konusunda haklısınız subprocess.run. Bununla birlikte, kodlar arasında kod paylaşmanın genel olarak daha iyi bir yolu, modüller oluşturmak ve komut dosyalarının birbirini komut dosyası olarak çağırmak yerine paylaşılan modülleri çağırmasını sağlamaktır. subprocess.runÇoğu hata ayıklayıcı işlem sınırlarını aşmadığından, çağrıları ayıklamak zordur , fazladan süreçler oluşturmak ve yok etmek için önemsiz olmayan sistem yükü ekleyebilir, vb.
Bay Fooz

4
düşünce bölümü için gıda foo2.py örneğinde bir şüphe var. foo2.py ithalat functionB ne yapar? Bence sadece functionB'den foo2.py ithal ediyor
user471651

1
@MrFooz Böyle bir şey yapmayı hiç düşünmemiştim Sadece aklıma geldi ve muhtemelen ppl'ye yardım etmek için garip olduğunu fark ettim. zihinlerini bu tür şeylerin etrafına sararak. @ user471651 Foo2'yi neden from foo2 import functionBfunctionB'den içe aktarmalısınız? Bu anlamsal bir bükülme. from module import methodyöntemi modülden alır.
hajef

2
Kodunuzu içe aktarabilecek modüllerden biri multiprocessing, özellikle bu testi Windows'da gerekli kılmaktır.
Yann Vernier

1801

Komut dosyanız Python yorumlayıcısına komut olarak iletilerek çalıştırıldığında,

python myscript.py

girinti düzeyinde 0 olan tüm kodlar yürütülür. Tanımlanan işlevler ve sınıflar iyi tanımlanmıştır, ancak kodlarının hiçbiri çalıştırılmaz. Diğer dillerden farklı olarak, main()otomatik olarak çalıştırılan bir işlev yoktur - main()işlev örtük olarak tüm kod üst düzeydedir.

Bu durumda, üst düzey kod bir ifbloktur. __name__geçerli modülün adını değerlendiren yerleşik bir değişkendir. Ancak, bir modül doğrudan çalıştırılıyorsa ( myscript.pyyukarıdaki gibi), __name__bunun yerine dizeye ayarlanır "__main__". Böylece, komut dosyanızın doğrudan çalıştırılıp çalıştırılmadığını veya başka bir şey tarafından içe aktarılıp aktarılmadığını test ederek test edebilirsiniz

if __name__ == "__main__":
    ...

Komut dosyanız başka bir modüle içe aktarılıyorsa, çeşitli işlev ve sınıf tanımları içe aktarılır ve üst düzey kodu yürütülür, ancak ifyukarıdaki fıkranın gövdesindeki kod koşul olarak çalışmaz karşılanmadı. Temel bir örnek olarak, aşağıdaki iki komut dosyasını göz önünde bulundurun:

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

Şimdi, tercümanı şu şekilde çağırırsanız:

python one.py

Çıktı

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

Eğer çalıştırırsanız two.pyyerine:

python two.py

Sen al

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

Böylece, modül oneyüklendiğinde, onun yerine __name__eşittir ."one""__main__"


Müthiş cevap, bu bence en açık cevaptı. 1!
TheTechRobo36414519

Bu şekilde düşünmek için +1: ilk girintili çizgi, ilk satırdaki işlevleri çalışana kadar yalnızca ilk başta çalıştırılır
Elijah Mock

719

İçin en basit açıklama __name__Değişken (imho) şudur:

Aşağıdaki dosyaları oluşturun.

# a.py
import b

ve

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

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

Onları çalıştırmak size şu çıktıyı verecektir:

$ python a.py
Hello World from b!

Gördüğünüz gibi, bir modül içe aktarıldığında, Python globals()['__name__']bu modülde modülün adını belirler. Ayrıca, içe aktarma üzerine modüldeki tüm kod çalıştırılmaktadır. İfadenin bu bölümü ifdeğerlendirdiği gibi Falseyürütülmez.

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

Gördüğünüz gibi, bir dosya yürütüldüğünde Python globals()['__name__']bu dosyada olarak ayarlanır "__main__". Bu kez ififade değerlendirilir Trueve çalıştırılır.


513

Ne yapar if __name__ == "__main__":?

Temel bilgileri özetlemek için:

  • Genel değişken, __name__programınıza giriş noktası olan modülde '__main__'. Aksi takdirde, modülü içe aktardığınız addır.

  • Bu nedenle, ifbloğun altındaki kod yalnızca modül programınıza giriş noktasıysa çalışır.

  • İçe aktarma işleminin altındaki kod bloğunu çalıştırmadan, modüldeki kodun diğer modüller tarafından içe aktarılmasını sağlar.


buna neden ihtiyacımız var?

Kodunuzu Geliştirme ve Test Etme

Modül olarak kullanılmak üzere tasarlanmış bir Python betiği yazdığınızı varsayalım:

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

Bu fonksiyon çağrısını en alta ekleyerek modülü test edebilirsiniz :

do_important()

ve (komut isteminde) aşağıdaki gibi bir şeyle çalıştırmak:

~$ python important.py

Sorun

Ancak, modülü başka bir komut dosyasına aktarmak istiyorsanız:

import important

İçe aktarma sırasında do_importantişlev çağrılır, böylece muhtemelen işlev çağrınızı do_important()en altta yorumlamanız gerekir .

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

Ve sonra test fonksiyonu çağrınızı yorumlayıp açıklamadığınızı hatırlamanız gerekir. Ve bu ekstra karmaşıklık, geliştirme sürecinizi daha zahmetli hale getirerek unutacağınız anlamına gelir.

En iyi yol

__name__Python yorumlayıcısı anda olur her yerde ad alanına değişken işaret eder.

İçe aktarılan bir modülün içinde, o modülün adıdır.

Ancak birincil modülün (veya etkileşimli bir Python oturumunun içinde, yani tercümanın Okuma, Değerlendirme, Baskı Döngüsü veya REPL) içinden her şeyi çalıştırıyorsunuz "__main__".

Dolayısıyla, çalıştırmadan önce kontrol ederseniz:

if __name__ == "__main__":
    do_important()

Yukarıdakilerle, kodunuz yalnızca birincil modül olarak çalıştırdığınızda (veya kasıtlı olarak başka bir komut dosyasından çağırdığınızda) yürütülür.

Daha İyi Bir Yol

Bununla birlikte, bunu geliştirmenin bir Pitonik yolu var.

Bu iş sürecini modülün dışından yürütmek istiyorsak ne olur?

Kodu geliştirir ve böyle bir işlevde test ederken egzersiz yapmak istersek, '__main__'hemen sonra kontrollerimizi yaparız :

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

Şimdi modülümüzün sonunda, modülü birincil modül olarak çalıştırırsak çalışacak son bir fonksiyonumuz var.

Modülün ve işlevlerinin ve sınıflarının işlevi çalıştırmadan diğer komut dosyalarına aktarılmasına mainizin verir ve ayrıca farklı bir '__main__'modülden çalışırken modülün (ve işlevlerinin ve sınıflarının) çağrılmasına izin verir , yani

import important
important.main()

Bu deyim, __main__modülün bir açıklamasında Python belgelerinde de bulunabilir . Bu metinde şunlar yazılıdır:

Bu modül, tercümanın ana programının yürüttüğü (aksi halde anonim) kapsamı temsil eder - standart girdiden, bir komut dosyasından veya etkileşimli bir istemden okunan komutlar. Deyimsel “koşullu betik” stanza'nın bir betiğin çalışmasına neden olduğu bu ortamdır:

if __name__ == '__main__':
    main()

125

if __name__ == "__main__"komut dosyası gibi bir komut kullanılarak komut satırından çalıştırıldığında (say) çalışan bölümdür python myscript.py.


2
Neden Bir dosya yok helloworld.pysadece birlikte print("hello world")o komut ile çalıştırabilirsiniz python helloworld.pyhiçbir olmasa bile if __name__ == "__main__"?
hi15

83

Ne yapar if __name__ == "__main__":?

__name__tüm ad alanlarında bulunan global bir değişkendir (Python'da global aslında modül düzeyinde anlamına gelir ). Genellikle modülün adıdır ( strtip olarak).

Bununla birlikte, tek özel durum olarak, çalıştırdığınız Python işlemlerinde mycode.py'de olduğu gibi:

python mycode.py

Aksi anonim genel ad değeri atanır '__main__'onun için __name__.

Böylece, son hatlar dahil

if __name__ == '__main__':
    main()
  • mycode.py betiğinizin sonunda,
  • bir Python işlemi tarafından çalıştırılan birincil, giriş noktası modülü olduğunda,

komut dosyanızın benzersiz olarak tanımlanmış mainişlevinin çalışmasına neden olur .

Bu yapıyı kullanmanın başka bir yararı: kodunuzu başka bir komut dosyasında bir modül olarak içe aktarabilir ve daha sonra programınız karar verirse ve ne zaman ana işlevi çalıştırabilirsiniz:

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

72

Burada, söz konusu kodun "Nasıl" mekaniği üzerinde birçok farklı şey var, ama benim için "Neden" i anlayana kadar hiçbiri anlamlı değildi. Bu özellikle yeni programcılar için yararlı olmalıdır.

"Ab.py" dosyasını al:

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

Ve ikinci bir dosya "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()

Bu kod aslında ne yapıyor?

Ne zaman idam xy.py, sen import ab. İmport deyimi, modülü içe aktarma sırasında hemen çalıştırdığından, abişlemleri 's geri kalanından önce yürütülür xy. İşiniz bittiğinde ab,xy .

Yorumlayıcı hangi komut dosyalarının çalıştığını izler __name__. Bir komut dosyası çalıştırdığınızda - adı ne olursa olsun - yorumlayıcı onu çağırır "__main__"ve dış komut dosyası çalıştırdıktan sonra geri dönen ana veya 'ev' komut dosyası yapar.

Bu "__main__"komut dosyasından çağrılan diğer komut dosyalarına dosya adı __name__(ör __name__ == "ab.py".) Olarak atanır . Dolayısıyla, çizgiif __name__ == "__main__": , başlangıçta yürütülen 'home' komut dosyasını yorumlayıp / ayrıştırmadığını veya geçici olarak başka bir (harici) komut dosyasına bakıp bakmadığını belirlemek için tercümanın testidir. Bu, programcıya harici olarak çağrıldığında doğrudan yürütüldüğünde komut dosyasının farklı davranması için esneklik sağlar.

Öncelikle girintisiz satırlara ve komut dosyalarında göründükleri sıraya odaklanarak, neler olduğunu anlamak için yukarıdaki kodu inceleyelim. Bu fonksiyon - veya def- bloklarının çağrılıncaya kadar kendi başlarına hiçbir şey yapmadığını unutmayın. Tercüman kendi kendine mırıldanırsa ne söyleyebilir:

  • Xy.py dosyasını 'home' dosyası olarak açın; diyoruz "__main__"içinde __name__değişken.
  • İle dosyayı içe aktarın ve açın __name__ == "ab.py".
  • Oh, bir fonksiyon. Bunu hatırlayacağım.
  • Tamam, fonksiyon a(); Bunu yeni öğrendim. ' Ab dosyasındaki bir işlev' yazdırılıyor .
  • Dosyanın sonu; geri dön "__main__"!
  • Oh, bir fonksiyon. Bunu hatırlayacağım.
  • Bir diğeri.
  • İşlev x(); tamam, ' çevresel görev: diğer projelerde yararlı olabilir ' yazdırma .
  • Bu nedir? Bir ifaçıklama. Peki, koşul karşılandı (değişken __name__olarak ayarlandı "__main__"), bu yüzden main()fonksiyona gireceğim ve ' ana fonksiyonunu yazacağım : bu, eylemin olduğu yerdir '.

Alttaki iki satır şu anlama gelir: "Bu "__main__"veya" home "komut dosyasıysa main()" adlı işlevi yürütün . " Bu yüzden def main():komut dosyasının işlevselliğinin ana akışını içeren bir blok yukarı göreceksiniz .

Bunu neden uygulamalıyım?

İthalat beyanları hakkında daha önce söylediğim şeyleri hatırlıyor musunuz? Bir modülü içe aktardığınızda, onu sadece 'tanımaz' ve daha fazla talimat beklemez - aslında kod içinde bulunan tüm yürütülebilir işlemleri çalıştırır. Bu nedenle, komut dosyanızın etini main()işleve etkili bir şekilde karantinaya alır, başka bir komut dosyası tarafından içe aktarıldığında hemen çalışmayacak şekilde yalıtır.

Yine, istisnalar olacaktır, ancak yaygın uygulama main()genellikle dışarıdan çağrılmaz. Yani bir şey daha merak ediyor olabilirsiniz: eğer aramıyorsak main(), senaryoyu neden çağırıyoruz? Birçok kişi komut dosyalarını dosyadaki kodun geri kalanından bağımsız olarak çalışmak üzere oluşturulmuş bağımsız işlevlerle yapılandırır. Daha sonra senaryo gövdesinde başka bir yere çağrılırlar. Bu da beni buna getiriyor:

Ancak kod onsuz çalışır

Evet bu doğru. Bu ayrı işlevler , bir işlevin içinde bulunmayan bir satır içi komut dosyasından çağrılabilir main(). Tam olarak ihtiyacınız olanı yapan satır içi komut dosyaları oluşturmaya alışkınsanız (benim gibi, programlamadaki ilk öğrenme aşamalarımda) ve bu işleme tekrar ihtiyacınız varsa tekrar anlamaya çalışacaksınız .. kodunuzun bu tür iç yapısına alışkın değilsiniz, çünkü oluşturmak daha karmaşıktır ve okumak sezgisel değildir.

Ancak bu muhtemelen işlevlerini harici olarak adlandırılamayan bir komut dosyasıdır, çünkü eğer öyleyse hemen değişkenleri hesaplamaya ve atamaya başlar. Ve bir işlevi yeniden kullanmaya çalışıyorsanız, yeni komut dosyanız eskisiyle çakışan değişkenler olacak kadar yakından ilişkilidir.

Bağımsız işlevleri böldüğünüzde, önceki çalışmanızı başka bir komut dosyasına çağırarak yeniden kullanma olanağına sahip olursunuz. Örneğin, "example.py" x(), "xy.py" den "xy.py" işlevini kullanarak "xy.py" dosyasını içe aktarabilir ve çağrı yapabilir. (Belli bir metin dizesinin üçüncü sözcüğünü büyük harfle yazıyor; bir sayı listesinden bir NumPy dizisi oluşturmak ve bunları karelemek; veya bir 3D yüzeyini küçültmek. Olasılıklar sınırsızdır.)

(Bu vesileyle, bu soruya nihayet anlamama yardımcı olduğunu @kindall kadar bir cevap içeriyor -. Neden değil how Ne yazık ki tekrarı olarak işaretlenmiş oldu bu bir ben bir hata olduğunu düşünüyorum.)


52

Modülümüzde ( M.py) ana (içe aktarılmamış) olarak çalıştırılacağı zaman yürütülmesini istediğimiz belirli ifadeler olduğunda, bu ifadeleri (test senaryoları, baskı ifadeleri) bu ifbloğun altına yerleştirebiliriz.

Varsayılan olarak (modül ana olarak çalışırken, içe aktarılmadığında) __name__değişken olarak ayarlanır "__main__"ve içe aktarılacağı zaman __name__değişken farklı bir değer, büyük olasılıkla modülün ( 'M') adını alır . Bu, modüllerin farklı varyantlarının birlikte çalıştırılmasında ve spesifik giriş ve çıkış ifadelerinin ayrılmasında ve ayrıca test senaryolarının bulunmasında yardımcı olur.

Kısacası , if __name__ == "main"modül içe aktarılırken (belirli) kodun çalışmasını önlemek için bu ' ' bloğu kullanın.


43

Basitçe söylemek gerekirse __name__, betiğin ana modül olarak mı yoksa içe aktarılan bir modül olarak mı çalıştığını tanımlayan her komut dosyası için tanımlanan bir değişkendir.

Yani iki senaryomuz varsa;

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

ve

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

Script1 yürütülmesinden elde edilen çıktı

Script 1's name: __main__

Ve script2'nin çalıştırılmasından elde edilen çıktı:

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

Gördüğünüz gibi __name__, bize hangi kodun 'ana' modül olduğunu söyler. Bu harika, çünkü sadece kod yazabiliyorsunuz ve C / C ++ gibi yapısal sorunlar hakkında endişelenmenize gerek yok, çünkü bir dosya 'ana' işlevi uygulamazsa, yürütülebilir olarak derlenemez ve eğer yaparsa, o zaman kütüphane olarak kullanılamaz.

Harika bir şey yapan bir Python betiği yazdığınızı ve başka amaçlar için yararlı olan bir tekne yükü işlevi uyguladığınızı varsayalım. Bunları kullanmak istersem, betiğinizi içe aktarabilir ve programınızı çalıştırmadan kullanabilirsiniz (kodunuzun yalnızca if __name__ == "__main__":bağlam içinde yürütüldüğü göz önüne alındığında ). Oysa C / C ++ 'da bu parçaları daha sonra dosyayı içeren ayrı bir modüle bölmelisiniz. Aşağıdaki durumu hayal edin;

C'de karmaşık içe aktarma

Oklar içe aktarma bağlantılarıdır. Her biri önceki modül kodunu eklemeye çalışan üç modül için altı dosya (dokuz, uygulama dosyalarını sayarak) ve beş bağlantı vardır. Bu, özel olarak bir kütüphane olarak derlenmedikçe, C projesine başka kodların eklenmesini zorlaştırır. Şimdi Python için hayal et:

Python'da zarif ithalat

Bir modül yazarsınız ve birisi kodunuzu kullanmak isterse onu içe aktarır ve __name__değişken, programın yürütülebilir bölümünü kitaplık bölümünden ayırmaya yardımcı olabilir.


2
C / C ++ çizimi yanlış: aynı birim adının 3 katı ( dosya1 ).
Kurt

40

Cevaba daha soyut bir şekilde bakalım:

Bu kodun elimizde olduğunu varsayalım x.py:

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

A ve B blokları koşarken çalışır x.py.

Ancak sadece A bloğu (B değil) başka bir modül çalıştırdığımızda çalıştırılır, y.pyörneğin x.pyiçeri aktarılır ve kod oradan çalıştırılır (bir işlev x.pyçağrıldığında olduğu gibi y.py).


1
Yayını düzenleyemedim (değişiklik gerekiyorsa en az 6 karakter). Satır 14'te 'x.py' yerine 'xy' var.
alwaysLearning

35

Python'u etkileşimli olarak çalıştırdığınızda yerel __name__değişkene bir değer atanır __main__. Benzer şekilde, bir Python modülünü başka bir modüle aktarmak yerine komut satırından yürüttüğünüzde, __name__özniteliğine modülün __main__gerçek adı yerine değeri atanır . Bu şekilde, modüller, __name__başka bir program için destek olarak veya komut satırından yürütülen ana uygulama olarak nasıl kullanıldıklarını kendileri belirlemek için kendi değerlerine bakabilirler . Bu nedenle, aşağıdaki deyim Python modüllerinde oldukça yaygındır:

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.

34

Düşünmek:

if __name__ == "__main__":
    main()

__name__Python betiğinin özniteliğinin olup olmadığını kontrol eder "__main__". Başka bir deyişle, programın kendisi yürütülürse, öznitelik olur __main__, bu nedenle program yürütülür (bu durumda main()işlev).

Ancak, Python betiğiniz bir modül tarafından kullanılıyorsa, ififadenin dışındaki herhangi bir kod yürütülür, bu nedenle if \__name__ == "\__main__"yalnızca programın modül olarak kullanılıp kullanılmadığını kontrol etmek için kullanılır ve bu nedenle kodun çalıştırılıp çalıştırılmayacağına karar verir.


parlak cevabı yazmak çok uzun zaman oldu +1
snr

27

Hakkında bir şey açıklamadan önce if __name__ == '__main__'ne __name__olduğunu ve ne yaptığını anlamak önemlidir .

Nedir __name__?

__name__bir DunderAlias - küresel bir değişken olarak düşünülebilir (modüllerden erişilebilir) ve benzer şekilde çalışırglobal .

Bu gösterildiği gibi (örneğin yukarıda belirtildiği gibi genel) bir dize type(__name__)elde edildi ( <class 'str'>), ve her ikisi için bir dahili standart Python 3 ve Python 2 alternatifler.

Nerede:

Yalnızca komut dosyalarında değil, aynı zamanda yorumlayıcıda ve modüllerde / paketlerde de bulunabilir.

Tercüman:

>>> print(__name__)
__main__
>>>

Senaryo:

test_file.py :

print(__name__)

Sonuçlanan __main__

Modül veya paket:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

Sonuçlanan somefile

Bir pakette veya modülde kullanıldığında __name__dosyanın adını aldığına dikkat edin. Gerçek modülün veya paket yolunun yolu verilmez, ancak buna __file__izin veren kendi DunderAlias'ı vardır .

Nerede, nerede __name__, nerede ana dosya (veya program) her zaman döneceğini __main__ve eğer bir modül / paket veya başka bir Python betiği çalıştıran bir şey varsa, dosyanın adını döndüreceğini görmelisiniz. kaynaklıdır.

Uygulama:

Değişken aracı olmak 's değeri o olabilir , ( "can" "gereken" değil ortalama yapar) değerini üzerine yazarak üzerine yazılır olmak__name__ okunabilirlik eksikliği neden olur. Yani herhangi bir nedenle yapmayın. Bir değişkene ihtiyacınız varsa yeni bir değişken tanımlayın.

Her zaman değerinin __name__olduğu __main__veya dosyanın adı olduğu varsayılır . Bir kez daha bu varsayılan değerin değiştirilmesi, iyi olacağı konusunda daha fazla karışıklığa neden olacak ve hatta daha da fazla sorunlara neden olacaktır.

misal:

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

Genellikle if __name__ == '__main__'senaryolara dahil etmek iyi bir uygulama olarak kabul edilir .

Şimdi cevaplayalım if __name__ == '__main__':

Artık __name__şeylerin davranışlarının daha net hale geldiğini biliyoruz :

An if, verilen değer doğruysa kod bloğunu içeren bir akış kontrol ifadesidir. Biz gördük __name__ya alabilir __main__ alındığı dosya adını veya adını .

Bu __name__, eşit ise __main__, dosyanın ana dosya olması ve komut dosyasına içe aktarılan bir modül veya paket değil, gerçekte çalışması (veya yorumlayıcı) olması gerektiği anlamına gelir .

Gerçekten __name__değeri alırsa __main__o kod bloğunda ne varsa onu yürütür.

Bu, çalışan dosya ana dosyaysa (veya doğrudan yorumlayıcıdan çalıştırıyorsanız), bu koşulun yürütülmesi gerektiğini belirtir. Bir paket ise, olmamalıdır ve değer olmayacaktır __main__.

Modüller:

__name__ bir modülün adını tanımlamak için modüllerde de kullanılabilir

Çeşitlemeler:

__name__Burada göstereceğim bazı , daha az yaygın ama yararlı şeyler yapmak da mümkündür :

Yalnızca dosya bir modül veya paketse yürütme:

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

Dosya ana dosyaysa bir koşul ve değilse:

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

Ayrıca, kitaplıkların ayrıntılı kullanımı olmadan paketler ve modüller üzerinde çalıştırılabilir yardım işlevleri / yardımcı programları sağlamak için de kullanabilirsiniz.

Ayrıca modüllerin komut satırından ana komut dosyaları olarak çalıştırılmasına izin verir, bu da çok yararlı olabilir.


25

Cevabı derinlemesine ve basit kelimelerle kırmanın en iyisi olduğunu düşünüyorum:

__name__: Python'daki her modülün özel bir özniteliği vardır __name__. Modülün adını döndüren yerleşik bir değişkendir.

__main__: Diğer programlama dilleri gibi, Python'un da bir yürütme giriş noktası vardır, yani ana. '__main__' üst düzey kodun yürütüldüğü kapsamın adıdır . Temel olarak bir Python modülü kullanmanın iki yolu vardır: Doğrudan komut dosyası olarak çalıştırın veya içe aktarın. Bir modül komut dosyası olarak çalıştırıldığında, modül olarak __name__ayarlanır __main__.

Böylece, modül ana program olarak çalıştırıldığında __name__özniteliğin değeri ayarlanır __main__. Aksi takdirde, değeri __name__ modülün adını içerecek şekilde ayarlanır.


23

Komut satırından bir Python dosyası çağrıldığında özeldir. Bu genellikle "main ()" işlevini çağırmak veya örneğin komut satırı bağımsız değişkenlerinin işlenmesi gibi diğer uygun başlangıç ​​kodlarını yürütmek için kullanılır.

Birkaç şekilde yazılabilir. Diğeri:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

Bunu üretim kodunda kullanmanız gerektiğini söylemiyorum ama bu konuda "büyülü" bir şey olmadığını göstermeye hizmet ediyor if __name__ == '__main__'. Python dosyalarında ana işlevi çağırmak için iyi bir kuraldır.


7
Bu kötü formu, 1) yan etkilere ve 2) istismara bağlı olarak düşünürüm and. andiki boole ifadesinin doğru olup olmadığını kontrol etmek için kullanılır. Sonuçlarıyla ilgilenmediğiniz için and, bir ififade niyetlerinizi daha açık bir şekilde iletir.
jpmc26

8
Bir akış kontrol mekanizması olarak boole operatörlerinin kısa devre davranışından yararlanılmasının kötü stil olup olmadığı sorusunu bir kenara bırakarak, daha büyük sorun bunun soruyu hiç cevaplamamasıdır .
Mark Amery

@MarkAmery haha, şeyh, şimdi öyle. 😊
Prof. Falken sözleşmesi

19

Sistemin (Python yorumlayıcısı) kaynak dosyalar (modüller) için sağladığı birkaç değişken vardır. Değerlerini istediğiniz zaman alabilirsiniz, bu yüzden __name__ değişkenine / niteliğine odaklanalım :

Python bir kaynak kod dosyası yüklediğinde, içinde bulunan tüm kodu yürütür. (Dosyada tanımlanan tüm yöntem ve işlevleri çağırmadığını, ancak bunları tanımladığını unutmayın.)

Yorumlayıcı kaynak kodu dosyasını çalıştırmadan önce, o dosya için birkaç özel değişken tanımlar; __name__ , Python'un her kaynak kod dosyası için otomatik olarak tanımladığı özel değişkenlerden biridir.

Python bu kaynak kodu dosyasını ana program (yani çalıştırdığınız dosya) olarak yüklüyorsa, bu dosyanın özel __name__ değişkenini "__main__" değerine sahip olacak şekilde ayarlar. .

Bu başka bir modülden içe aktarılıyorsa __name__ bu modülün adına ayarlanacaktır.

Yani, örneğinizde kısmen:

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

kod bloğunun:

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

yalnızca modülü doğrudan çalıştırdığınızda yürütülür; başka bir modül onu çağırıyor / içeri aktarıyorsa kod bloğu yürütülmez çünkü __name__ değeri bu örnekte " main " değerine eşit olmaz .

Umarım bu yardımcı olur.


17

if __name__ == "__main__": temelde en üst düzey komut dosyası ortamıdır ve ('önce yürütülecek en yüksek önceliğe sahibim') yorumlayıcısını belirtir.

'__main__'üst düzey kodun yürütüldüğü kapsamın adıdır. Bir modül , standart girişten, bir komut dosyasından veya etkileşimli bir istemden okunduğunda __name__eşittir '__main__'.

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

17

Bu sayfadaki cevaplar boyunca çok şey okudum. Şunu söyleyebilirim ki, eğer bir şey biliyorsanız, kesinlikle bu cevapları anlayacaksınız, aksi takdirde hala kafanız karıştı.

Kısa olmak için birkaç nokta bilmeniz gerekir:

  1. import a eylem aslında "a" da çalıştırılabilen her şeyi çalıştırır

  2. Nokta 1 nedeniyle, içe aktarırken her şeyin "a" içinde çalıştırılmasını istemeyebilirsiniz.

  3. Nokta 2'deki sorunu çözmek için, python bir koşul kontrolü yapmanıza izin verir

  4. __name__tüm .pymodüllerde örtük bir değişkendir ; ne zaman a.pyalınır, değeri __name__ve a.pymodül dosya adı "olarak ayarlandığında a"; ne zaman a.py"kullanılarak direkt olarak çalıştırılan python a.py," olan bir araç a.pygiriş noktası olup, daha sonra değeri __name__arasında a.pymodülünün bir dizi ayarlanır__main__

  5. Python'un __name__her modül için değişkeni nasıl ayarladığı mekanizmasına dayanarak, 3. noktaya nasıl ulaşacağınızı biliyor musunuz? Cevap oldukça kolay, değil mi? Bir if koşulu koyun if __name__ == "__main__": ...:; __name__ == "a"fonksiyonel ihtiyacınıza göre bile koyabilirsiniz

Python'un özel olması önemli olan nokta 4! Gerisi sadece temel mantık.


1
Evet, 1. nokta anlamak için çok önemlidir. Bundan sonra, bu mekanizmaya duyulan ihtiyaç netleşir.
Eureka

16

Düşünmek:

print __name__

Yukarıdakiler için çıktı __main__ .

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

Yukarıdaki ifade doğrudur ve "doğrudan yöntem" yazdırır . Bu sınıfı başka bir sınıfta içe aktarmışlarsa, "doğrudan yöntem" yazdırmazlarsa , içe aktarırken ayarlanacağını varsayalım __name__ equal to "first model name".


14

Dosyayı komut dosyası olarak ve içe aktarılabilir bir modül olarak kullanılabilir hale getirebilirsiniz .

fibo.py (adlı bir modül 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]))

Referans: https://docs.python.org/3.5/tutorial/modules.html


14

Nedeni

if __name__ == "__main__":
    main()

öncelikle kodun doğrudan içe aktarılmasından kaynaklanacak ithalat kilit sorunlarından kaçınmaktır . Dosyanız doğrudan çağrıldıysa (bu durumda) çalıştırmak istiyorsunuz , ancak kodunuz içe aktarılmışsa, ithalatçı kilit sorunlarını önlemek için ithalatçı kodunuzu gerçek ana modülden girmelidir.main()__name__ == "__main__"

Yan etki, otomatik olarak birden çok giriş noktasını destekleyen bir metodolojide oturum açmanızdır. Programınızı main()giriş noktası olarak kullanarak çalıştırabilirsiniz , ancak zorunlu değildir . İken setup.pybeklentiden main(), diğer araçlar alternatif giriş noktaları kullanırlar. Örneğin, dosyanızı bir gunicornişlem olarak çalıştırmak için a app()yerine bir işlev tanımlarsınız main(). Tıpkı olduğu gibi setup.py, gunicornkodunuzu içe aktarır, böylece içe aktarılırken hiçbir şey yapmasını istemezsiniz (içe aktarma kilidi sorunu nedeniyle).


3
İthalat kilidi hakkında bilgi edinmek güzel . Lütfen [...] biraz daha parçası olan bir metodolojide oturum açmayı açıklar mısınız?
Kurt

1
@Wolf: Elbette. Çoklu giriş noktaları metodolojisi hakkında birkaç cümle ekledim.
personal_cloud

11

Bu cevap Python'u öğrenen Java programcıları içindir. Her Java dosyası genellikle bir ortak sınıf içerir. Bu sınıfı iki şekilde kullanabilirsiniz:

  1. Sınıfı diğer dosyalardan arayın. Sadece arama programına aktarmanız gerekir.

  2. Test amacıyla sınıfı tek başına çalıştırın.

İkinci durumda, sınıf bir genel statik void main () yöntemi içermelidir. Python'da bu amaca global olarak tanımlanmış etiket hizmet vermektedir '__main__'.


11

Aşağıdaki kod if __name__ == '__main__': yalnızca modül komut dosyası olarak çağrıldığında çalıştırılır .

Örnek olarak aşağıdaki modülü göz önünde bulundurun my_test_module.py:

# my_test_module.py

print('This is going to be printed out, no matter what')

if __name__ == '__main__':
    print('This is going to be printed out, only if user invokes the module as a script')

1. olasılık: my_test_module.pyBaşka bir modüle içe aktarma

# main.py

import my_test_module

if __name__ == '__main__':
    print('Hello from main.py')

Şimdi çağırırsanız main.py:

python main.py 

>> 'This is going to be printed out, no matter what'
>> 'Hello from main.py'

Yalnızca üst düzey print()deyimin my_test_moduleyürütüldüğünü unutmayın.


2. olasılık: my_test_module.pySenaryo olarak çağır

Şimdi my_test_module.pybir Python betiği olarak çalıştırırsanız , her iki print()ifade de uygulanacaktır:

python my_test_module.py

>>> 'This is going to be printed out, no matter what'
>>> 'This is going to be printed out, only if user invokes the module as a script'

10

Python'daki her modülün bir özniteliği vardır __name__. __name__ Özniteliğin değeri __main__ , modülün doğrudan çalıştırıldığı zamandır python my_module.py. Aksi takdirde (dediğin gibi import my_module) değeri __name__ modülün adıdır.

Kısaca açıklamak için küçük bir örnek.

#Script test.py

apple = 42

def hello_world():
    print("I am inside hello_world")

if __name__ == "__main__":
    print("Value of __name__ is: ", __name__)
    print("Going to call hello_world")
    hello_world()

Bunu doğrudan şu şekilde yürütebiliriz:

python test.py  

Çıktı

Value of __name__ is: __main__
Going to call hello_world
I am inside hello_world

Şimdi varsayalım ki yukarıdaki komut dosyasını başka bir komut dosyasından çağırıyoruz

#script external_calling.py

import test
print(test.apple)
test.hello_world()

print(test.__name__)

Bunu yürüttüğünde

python external_calling.py

Çıktı

42
I am inside hello_world
test

Yani, yukarıda öz döngü eğer, diğer komut dosyasından testi çağırdığınızda o ölçüde ifade etmektedir __name__içinde test.pyçalıştırmaz.


6

Bu .py dosyası diğer .py dosyaları tarafından içe aktarılırsa, "if ifadesi" altındaki kod yürütülmez.

Bu .py python this_py.pykabuk altında çalıştırılırsa veya Windows'ta çift tıklanırsa. "if ifadesi" altındaki kod yürütülür.

Genellikle test için yazılır.


6

Python yorumlayıcısı belirli bir modülü çalıştırıyorsa, __name__global değişkenin değeri olacaktır"__main__"

  def a():
      print("a")
  def b():
      print("b")

  if __name__ == "__main__": 

          print ("you can see me" )
          a()
  else: 

          print ("You can't see me")
          b()

Bu senaryo baskılarını çalıştırdığınızda beni görebilirsiniz

bir

Sonra dosya B dosya B'ye Bu dosyayı diyelim A içe ve yürütmek durumunda if __name__ == "__main__"dosyada o yazdırır böylece A, yanlış olur Beni göremez

b


5

Tüm cevaplar işlevselliği hemen hemen açıkladı. Ancak, kavramın daha fazla temizlenmesine yardımcı olabilecek kullanımının bir örneğini sunacağım.

A.py ve b.py olmak üzere iki Python dosyanız olduğunu varsayın. Şimdi, a.py b.py'yi ithal ediyor. İlk olarak "import b.py" kodunun yürütüldüğü a.py dosyasını çalıştırıyoruz. A.py kodunun geri kalanı çalışmadan önce, b.py dosyasındaki kodun tamamen çalışması gerekir.

B.py kodunda, b.py dosyasına özel olan bazı kodlar vardır ve b.py dosyasını içe aktarmış olan başka bir dosya (b.py dosyası dışında) çalıştırmak istemeyiz.

İşte bu kod satırı kontrol eder. Kodu çalıştıran ana dosya (yani, b.py) ise, bu durumda (a.py çalışan ana dosyadır) değilse, yalnızca kod yürütülür.


4

Bir dosya oluşturun, a.py :

print(__name__) # It will print out __main__

__name__her zaman eşittir __main__bu dosya olduğu yerlerde doğrudan işletilen bu ana dosyası olduğunu gösteren.

Aynı dizinde başka bir dosya, b.py oluşturun :

import a  # Prints a

Çalıştır. Bu yazdırılacaktır bir , yani dosyanın adını ithal edilmektedir .

Dolayısıyla, aynı dosyanın iki farklı davranışını göstermek için , bu yaygın olarak kullanılan bir numaradır:

# Code to be run when imported into another python file

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

4

eğer adı == ' ana ':

__name__ == '__main__':Oldukça sık olup olmadığını görüyoruz .

Bir modülün içe aktarılıp aktarılmadığını kontrol eder.

Başka bir deyişle, ifblok içindeki kod yalnızca kod doğrudan çalıştığında yürütülür. İşte directlydemek not imported.

Modülün adını yazdıran basit bir kod kullanarak ne yaptığını görelim:

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

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

Kodu doğrudan üzerinden çalıştırırsak python test.py, modül adı __main__:

call test()
test module name=__main__

4

Basitçe, dosyayı C programlama dilindeki mainişlev gibi çalıştırmak için giriş noktasıdır .


8
Bu cevap OP (veya benzer soru ile herhangi bir kullanıcı) ile her iki tanıdık bir varsayım yapar C ve giriş noktasıdır bilir.
arredond

1
Bu cevap ayrıca, hiçbir kodun (yan etkisi olmayan tanımlar dışında) if __name__ == "__main__"bloktan önce gerçekleşmediğini varsayar . Teknik olarak yürütülen komut dosyasının en üst kısmı programın giriş noktasıdır.
Charlie Harding
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.