Co robi polecenie 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))
Kiedy interpreter Pythona wczytuje plik źródłowy, robi dwie rzeczy:
__name__
, a następnie__name__
, które zawsze widzimy w skryptach Pythona.
Przykładowy kodUżyjmy nieco innej próbki kodu, aby zbadać, jak działa import i skrypty. Załóżmy, że w pliku o nazwie foo.py
znajduje się następująca treść.
# 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")
Kiedy interpreter Pythona wczytuje plik źródłowy, najpierw definiuje kilka zmiennych specjalnych. W tym przypadku zależy nam na zmiennej __name__
.
Gdy Twój moduł jest programem głównym
Jeśli uruchamiasz swój moduł (plik źródłowy) jako program główny, np.
python foo.py
to interpreter przypisze ciąg "__main__"
do zmiennej __name__
, tzn.
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Kiedy twój moduł jest importowany przez inny Z drugiej strony, załóżmy, że jakiś inny moduł jest programem głównym i importuje twój moduł. Oznacza to, że w głównym programie lub w innym module, który importuje główny program, znajduje się taka instrukcja:
# Suppose this is in some other main program.
import foo
W tym przypadku, interpreter spojrzy na nazwę pliku twojego modułu, foo.py
, usunie .py
i przypisze ten łańcuch do zmiennej __name__
twojego modułu' tzn.
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Po skonfigurowaniu zmiennych specjalnych, interpreter wykonuje cały kod modułu, po jednej instrukcji na raz. Być może zechcesz otworzyć inne okno na stronie z przykładem kodu, aby móc śledzić to wyjaśnienie. Zawsze
"przed importem"
(bez cudzysłowów).math
i przypisuje go do zmiennej o nazwie math
. Jest to równoważne zastąpieniu import math
następującym (zauważ, że __import__
jest niskopoziomową funkcją w Pythonie, która pobiera łańcuch i wywołuje rzeczywisty import):# Znajdź i załaduj moduł podając jego nazwę łańcuchową, "math",
# a następnie przypisz go do zmiennej lokalnej o nazwie math.
math = __import__("math")
"przed funkcjąA"
.def
, tworząc obiekt funkcji, a następnie przypisując ten obiekt funkcji do zmiennej o nazwie functionA
."before functionB"
.def
, tworząc kolejny obiekt funkcji, a następnie przypisując go do zmiennej o nazwie functionB
."before __name__ guard"
.
Tylko wtedy, gdy twój moduł jest programem głównym.__name__
rzeczywiście został ustawiony na "__main__"
i wywoła dwie funkcje, wypisując łańcuchy "Funkcja A"
i "Funkcja B 10.0"
.
Tylko wtedy, gdy twój moduł jest importowany przez inny.__name__
będzie "foo"
, a nie "__main__"
, i'pominie ciało instrukcji if
.
Zawsze"po __name__ guard"
w obu sytuacjach.
Podsumowanie
Podsumowując, oto'co'zostałoby wydrukowane w tych dwóch przypadkach:
# 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
Możesz naturalnie zastanawiać się, dlaczego ktokolwiek chciałby tego. Otóż, czasami chcesz napisać plik .py
, który może być zarówno używany przez inne programy i/lub moduły jako moduł, jak i może być uruchamiany jako program główny. Przykłady:
Twój moduł jest biblioteką, ale chcesz mieć tryb skryptowy, w którym uruchamia on jakieś testy jednostkowe lub demo.
Twój moduł jest używany tylko jako program główny, ale ma kilka testów jednostkowych, a framework testowy działa poprzez importowanie plików .py
jak twój skrypt i uruchamianie specjalnych funkcji testowych. Nie chcesz, aby próbował on uruchomić skrypt tylko dlatego, że importuje moduł.
Pytanie: Czy mogę mieć wiele bloków sprawdzających __name__
? Odpowiedź: Jest to dziwne, ale język nie będzie cię powstrzymywał.
Przypuśćmy, że poniższy tekst znajduje się w pliku foo2.py
. Co się stanie, jeśli powiesz python foo2.py
w wierszu poleceń? Dlaczego?
# 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")
__name__
w 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")
# Suppose this is in foo4.py
__name__ = "__main__"
def bar():
print("bar")
print("before __name__ guard")
if __name__ == "__main__":
bar()
print("after __name__ guard")
Kiedy twój skrypt jest uruchamiany przez przekazanie go jako polecenia do interpretera Pythona,
python myscript.py
wykonywany jest cały kod, który znajduje się na poziomie wcięcia 0. Funkcje i klasy, które są zdefiniowane, są, no cóż, zdefiniowane, ale żaden z ich kodu nie zostanie wykonany. W przeciwieństwie do innych języków, nie ma funkcji main()
, która jest uruchamiana automatycznie - funkcja main()
jest domyślnie całym kodem na najwyższym poziomie.
W tym przypadku, kodem najwyższego poziomu jest blok if
. name__
jest wbudowaną zmienną, która odpowiada nazwie bieżącego modułu. Jednakże, jeśli moduł jest uruchamiany bezpośrednio (jak w myscript.py
powyżej), wtedy __name__
jest ustawiane na łańcuch "__main__"
. Tak więc, możesz sprawdzić czy twój skrypt jest uruchamiany bezpośrednio, czy też jest importowany przez coś innego, testując
if __name__ == "__main__":
...
Jeśli twój skrypt jest importowany do innego modułu, jego różne definicje funkcji i klas zostaną zaimportowane i jego kod najwyższego poziomu zostanie wykonany, ale kod w then-body powyższej klauzuli if
nie zostanie uruchomiony, ponieważ warunek nie jest spełniony. Jako podstawowy przykład, rozważmy następujące dwa skrypty:
# 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")
Teraz, jeśli wywołasz interpreter jako
python one.py
Wyjściem będzie
top-level in one.py
one.py is being run directly
Jeśli zamiast tego uruchomisz two.py
:
python two.py
Otrzymasz
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
Tak więc, kiedy moduł one
zostaje załadowany, jego __name__
równa się "one"
zamiast "__main__"
.
if __name__ == "__main__"
jest częścią, która jest uruchamiana, gdy skrypt jest uruchamiany z (powiedzmy) linii poleceń za pomocą komendy takiej jak python myscript.py
.