Wat doet if __name__ == "__main__":?

Wat doet de 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))
Oplossing

Wanneer de Python interpreter een bronbestand leest, doet hij twee dingen:

  • het stelt een paar speciale variabelen in zoals __name__, en dan
  • voert hij alle code uit die in het bestand staat.

Laten we eens kijken hoe dit werkt en hoe het verband houdt met je vraag over de __name__ controles die we altijd zien in Python scripts. Code Voorbeeld

Laten we een iets ander codevoorbeeld gebruiken om te onderzoeken hoe imports en scripts werken. Stel dat het volgende in een bestand genaamd foo.py staat.

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

Speciale Variabelen

Wanneer de Python interpeter een bronbestand leest, definieert hij eerst een paar speciale variabelen. In dit geval gaat het om de __name__ variabele. Wanneer uw module het hoofdprogramma is Als je je module (het bronbestand) als het hoofdprogramma uitvoert, bijv.

python foo.py

zal de interpreter de hard-coded string "__main__" toewijzen aan de __name__ variabele, d.w.z.

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

Wanneer uw module wordt geïmporteerd door een andere Aan de andere kant, stel dat een andere module het hoofdprogramma is en het importeert jouw module. Dit betekent dat er een verklaring als deze is in het hoofdprogramma, of in een andere module die het hoofdprogramma importeert:

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

In dit geval kijkt de interpreter naar de bestandsnaam van uw module, foo.py, haalt de .py weg, en wijst die string toe aan uw module's __name__ variabele, d.w.z.

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

Uitvoeren van de module's code

Nadat de speciale variabelen zijn ingesteld, voert de interpreter alle code in de module uit, één statement per keer. U wilt misschien een ander venster openen aan de zijkant met het codevoorbeeld, zodat u deze uitleg kunt volgen. Altijd

  1. Het drukt de string "before import" af (zonder aanhalingstekens).
  2. Het laadt de math module en wijst het toe aan een variabele genaamd math. Dit is equivalent aan het vervangen van import math door het volgende (merk op dat __import__ een low-level functie in Python is die een string neemt en de eigenlijke import in gang zet):
    # Zoek en laad een module met zijn stringnaam, "math",
    # en wijs het dan toe aan een lokale variabele genaamd math.
    math = __import__("math")
  3. Het drukt de string "before functionA" af.
  4. Het voert het def blok uit, creëert een functie object en wijst dat functie object toe aan een variabele genaamd functionA.
  5. Het drukt de string "before functionB" af.
  6. Het tweede def-blok wordt uitgevoerd, waarbij een ander functieobject wordt aangemaakt en vervolgens wordt toegewezen aan een variabele met de naam functieB.
  7. Het drukt de string "before __name__ guard" af. Alleen als je module het hoofdprogramma is
  8. Als uw module het hoofdprogramma is, dan zal het zien dat __name__ inderdaad is ingesteld op "__main__" en het roept de twee functies aan, waarbij de strings "Function A" en "Function B 10.0" worden afgedrukt. Alleen wanneer uw module door een ander wordt geïmporteerd
  9. (in plaats daarvan) Als uw module niet het hoofdprogramma is, maar is geïmporteerd door een ander, dan zal __name__ "foo" zijn, en niet "__main__", en het'zal de body van de if verklaring overslaan. Altijd
  10. Het zal de string "na __name__ guard" in beide situaties afdrukken. Samenvatting Samenvattend, hier'is wat'in de twee gevallen zou worden afgedrukt:
# 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

Waarom werkt het op deze manier?

Je zou je natuurlijk kunnen afvragen waarom iemand dit zou willen. Wel, soms wil je een .py bestand schrijven dat zowel gebruikt kan worden door andere programma's en/of modules als een module, en ook als het hoofdprogramma zelf kan worden uitgevoerd. Voorbeelden:

  • Uw module is een bibliotheek, maar u wilt een script modus hebben waar het een aantal unit tests of een demo uitvoert.

  • Uw module wordt alleen gebruikt als hoofdprogramma, maar het heeft een aantal unit tests, en het test framework werkt door het importeren van .py bestanden zoals uw script en het uitvoeren van speciale test functies. Je wilt niet dat het probeert het script uit te voeren alleen omdat het de module importeert.

  • Uw module wordt meestal gebruikt als een hoofdprogramma, maar het biedt ook een programmeur-vriendelijke API voor gevorderde gebruikers. Buiten deze voorbeelden, is het's elegant dat het uitvoeren van een script in Python gewoon het instellen van een paar magische variabelen is en het importeren van het script. "Running" het script is een neveneffect van het importeren van de module van het script's. Voedsel voor de geest

  • Vraag: Kan ik meerdere __name__ controlerende blokken hebben? Antwoord: het'is vreemd om dat te doen, maar de taal zal'je niet tegenhouden.

  • Stel dat het volgende in foo2.py staat. Wat gebeurt er als je python foo2.py zegt op de command-line? Waarom?

# 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")
  • Zoek nu uit wat er gebeurt als je de __name__ check in foo3.py verwijdert:
# 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")
  • Wat zal dit doen als het gebruikt wordt als een script? Als het geïmporteerd wordt als een module?
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")

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

Wanneer uw script wordt uitgevoerd door het als een commando aan de Python interpreter door te geven,

python myscript.py

wordt alle code uitgevoerd die op inspringniveau 0 staat. Functies en klassen die gedefinieerd zijn, nou ja, gedefinieerd, maar niets van hun code wordt uitgevoerd. In tegenstelling tot andere talen, is er geen main() functie die automatisch wordt uitgevoerd - de main() functie is impliciet alle code op het hoogste niveau.

In dit geval is de top-level code een if blok. __name__ is een ingebouwde variabele die evalueert naar de naam van de huidige module. Echter, als een module direct wordt uitgevoerd (zoals in myscript.py hierboven), dan wordt __name__ in plaats daarvan ingesteld op de string "__main__". U kunt dus testen of uw script direct wordt uitgevoerd of door iets anders wordt geïmporteerd door te testen

if __name__ == "__main__":
    ...

Als uw script wordt geïmporteerd in een andere module, zullen de verschillende functie en klasse definities worden geïmporteerd en de top-level code zal worden uitgevoerd, maar de code in de then-body van de if clausule hierboven zal niet worden uitgevoerd omdat niet aan de voorwaarde is voldaan. Als een basisvoorbeeld, beschouw de volgende twee scripts:

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

Nu, als je de interpreter aanroept als

python one.py

De uitvoer zal zijn

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

Als je in plaats daarvan two.py uitvoert:

python two.py

Je krijgt

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

Dus, als module one wordt geladen, is zijn __name__ gelijk aan "one" in plaats van "__main__".

Commentaren (0)

if __name__ == "__main__" is het deel dat wordt uitgevoerd als het script wordt uitgevoerd vanaf (zeg) de commandoregel met een commando als python myscript.py.

Commentaren (1)