Kaj naredi 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))
Ko prevajalnik Python prebere izvorno datoteko, stori dve stvari:
__name__
, nato pa__name__
, ki ga vedno vidimo v Pythonovih skriptih.
Vzorec kodeUporabimo nekoliko drugačen vzorec kode, da bi raziskali, kako delujejo uvozi in skripte. V datoteki z imenom foo.py
je recimo naslednje.
# 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")
Ko vmesnik Python prebere izvorno datoteko, najprej definira nekaj posebnih spremenljivk. V tem primeru nas zanima spremenljivka __name__
.
Ko je vaš modul glavni program
Če svoj modul (izvorno datoteko) zaženete kot glavni program, npr.
python foo.py
bo prevajalnik spremenljivki __name__`` pripisal težko kodiran niz
"main"`, tj.
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Ko vaš modul uvozi drug modul Po drugi strani pa predpostavimo, da je nek drug modul glavni program in uvozi vaš modul. To pomeni, da je v glavnem programu ali v nekem drugem modulu, ki ga uvaža glavni program, takšna izjava:
# Suppose this is in some other main program.
import foo
V tem primeru bo prevajalnik pogledal ime datoteke vašega modula, foo.py
, odstranil .py
in ta niz pripisal spremenljivki __name__
vašega modula, tj.
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Ko so posebne spremenljivke nastavljene, tolmač izvede vso kodo v modulu, eno izjavo naenkrat. Morda boste želeli odpreti drugo okno na strani z vzorcem kode, da boste lahko sledili tej razlagi. Vedno
"pred uvozom"
(brez narekovajev).math
in ga dodeli spremenljivki z imenom math
. To je enakovredno zamenjavi import math
z naslednjim (upoštevajte, da je __import__
nizkonivojska funkcija v Pythonu, ki sprejme niz in sproži dejanski uvoz):# Poišči in naloži modul glede na njegovo ime v nizu, "math",
# nato ga pripišemo lokalni spremenljivki z imenom math.
math = __import__("math")
"pred funkcijoA"
.def
, pri čemer ustvari objekt funkcije, nato pa ta objekt funkcije dodeli spremenljivki z imenom funkcijaA
."pred funkcijoB"
.def
, pri čemer ustvari še en objekt funkcije in ga dodeli spremenljivki z imenom funkcijaB
."before __name__ guard"
.
Tudi kadar je vaš modul glavni program__name__
res nastavljen na "__main__"
, poklical obe funkciji in izpiše niza "Funkcija A"
in "Funkcija B 10.0"
.
Tudi ko vaš modul uvozi drug modul__name__
"foo"
in ne "__main__"
ter bo preskočil telo izjave if
.
Vedno"after __name__ guard"
.
Povzetek
Če povzamemo, je tukaj'to, kar bi se izpisalo v obeh primerih:
# 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
Morda se sprašujete, zakaj bi si kdo to želel. No, včasih želite napisati datoteko .py
, ki jo lahko uporabljajo drugi programi in/ali moduli kot modul, lahko pa jo zaženete tudi kot glavni program. Primeri:
Vaš modul je knjižnica, vendar želite imeti skriptni način, v katerem se zaženejo nekateri testi enote ali demo program.
Vaš modul se uporablja samo kot glavni program, vendar ima nekaj testov enote, ogrodje za testiranje pa deluje tako, da uvozi datoteke .py
kot vaša skripta in zažene posebne testne funkcije. Ne želite, da poskuša zagnati skripto samo zato, ker uvozi modul.
Vprašanje: Ali imam lahko več blokov za preverjanje __name__
? Odgovor: To je čudno, vendar vam jezik tega ne bo preprečil.
Predpostavimo, da je v foo2.py
naslednje. Kaj se zgodi, če v ukazni vrstici rečete python foo2.py
? Zakaj?
# 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__
v 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")
Ko se vaša skripta zažene, jo kot ukaz posredujete tolmaču Pythona,
python myscript.py
se izvede vsa koda, ki je na ravni alineje 0. Funkcije in razredi, ki so definirani, so definirani, vendar se nobena njihova koda ne izvede. Za razliko od drugih jezikov ni funkcije main()
, ki bi se izvajala samodejno - funkcija main()
je implicitno vsa koda na najvišji ravni.
V tem primeru je koda na najvišji ravni blok if
. __name__
je vgrajena spremenljivka, ki se ovrednoti z imenom trenutnega modula. Če pa se modul izvaja neposredno (kot v myscript.py
zgoraj), se __name__
namesto tega nastavi na niz "__main__"
. Tako lahko preverite, ali se vaša skripta izvaja neposredno ali pa jo uvaža nekaj drugega, tako da testirate
if __name__ == "__main__":
...
Če je vaša skripta uvožena v drug modul, bodo njene različne definicije funkcij in razredov uvožene in njena koda na najvišji ravni se bo izvršila, vendar se koda v then-body zgornje klavzule if
ne bo izvedla, ker pogoj ni izpolnjen. Kot osnovni primer si oglejte naslednji dve skripti:
# 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")
Če zdaj tolmača prikličete kot
python one.py
Rezultat bo
top-level in one.py
one.py is being run directly
Če namesto tega zaženete two.py
:
python two.py
Dobili boste
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
Ko se torej naloži modul one
, je njegovo __name__
enako "one"
namesto "__main__"
.
if __name__ == "__main__"
je del, ki se zažene, ko se skripta zažene iz (recimo) ukazne vrstice z ukazom, kot je python myscript.py
.