Che cosa fa il 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))
Ogni volta che l'interprete Python legge un file sorgente, fa due cose:
__name__
, e poi__name__
che vediamo sempre negli script Python.
Esempio di codiceUsiamo un esempio di codice leggermente diverso per esplorare come funzionano le importazioni e gli script. Supponiamo che quanto segue sia in un file chiamato 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")
Quando l'interprete Python legge un file sorgente, prima definisce alcune variabili speciali. In questo caso, ci interessa la variabile __name__
.
Quando il vostro modulo è il programma principale
Se state eseguendo il vostro modulo (il file sorgente) come programma principale, ad esempio
python foo.py
l'interprete assegnerà la stringa "__main__"
alla variabile __name__
, cioè
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Quando il tuo modulo è importato da un altro D'altra parte, supponiamo che qualche altro modulo sia il programma principale e importi il vostro modulo. Questo significa che c'è una dichiarazione come questa nel programma principale, o in qualche altro modulo che il programma principale importa:
# Suppose this is in some other main program.
import foo
In questo caso, l'interprete guarderà il nome del tuo modulo, foo.py
, toglierà il .py
, e assegnerà quella stringa alla variabile __name__
del tuo modulo, cioè
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Dopo che le variabili speciali sono state impostate, l'interprete esegue tutto il codice del modulo, un'istruzione alla volta. Potreste voler aprire un'altra finestra sul lato con l'esempio di codice in modo da poter seguire questa spiegazione. Sempre
"before import"
(senza virgolette).math
e lo assegna ad una variabile chiamata math
. Questo equivale a sostituire import math
con quanto segue (si noti che __import__
è una funzione di basso livello in Python che prende una stringa e innesca l'effettiva importazione):# Trova e carica un modulo dato il suo nome stringa, "math",
# poi lo assegna ad una variabile locale chiamata math.
math = __import__("math")
"prima della funzioneA"
.def
, creando un oggetto funzione, poi assegna tale oggetto funzione ad una variabile chiamata funzioneA
."prima della funzioneB"
.def
, creando un altro oggetto funzione, poi assegnandolo ad una variabile chiamata funzioneB
."before __name__ guard"
.
Solo quando il vostro modulo è il programma principale__name__
è stato effettivamente impostato a "__main__"
e chiama le due funzioni, stampando le stringhe "Funzione A"
e "Funzione B 10.0"
.
Solo quando il vostro modulo è importato da un altro__name__
sarà "foo"
, non "__main__"
, e salterà il corpo della dichiarazione if
.
Sempre"dopo __name__ guard"
in entrambe le situazioni.
Sommario
In sintesi, ecco cosa verrebbe stampato nei due casi:# 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
Potreste naturalmente chiedervi perché qualcuno dovrebbe volere questo. Beh, a volte si vuole scrivere un file .py
che può essere sia usato da altri programmi e/o moduli come un modulo, e può anche essere eseguito come programma principale stesso. Esempi:
Il vostro modulo è una libreria, ma volete avere una modalità script in cui eseguire alcuni test unitari o una demo.
Il tuo modulo è usato solo come programma principale, ma ha alcuni test unitari, e il framework di test funziona importando file .py
come il tuo script ed eseguendo speciali funzioni di test. Non volete che provi ad eseguire lo script solo perché sta importando il modulo.
Domanda: Posso avere più blocchi di controllo __name__
? Risposta: è strano farlo, ma il linguaggio non te lo impedisce.
Supponiamo che il seguente sia in foo2.py
. Cosa succede se dite python foo2.py
sulla linea di comando? Perché?
-- lingua: python -->
# 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__
in 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")
}}Lingua: python -->
# 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")
Quando il tuo script viene eseguito passandolo come comando all'interprete Python,
python myscript.py
tutto il codice che è al livello di indentazione 0 viene eseguito. Le funzioni e le classi che sono definite sono, beh, definite, ma nessuno del loro codice viene eseguito. A differenza di altri linguaggi, non c'è una funzione main()
che viene eseguita automaticamente - la funzione main()
è implicitamente tutto il codice al livello superiore.
In questo caso, il codice di primo livello è un blocco if
. __name__
è una variabile incorporata che valuta il nome del modulo corrente. Tuttavia, se un modulo viene eseguito direttamente (come in myscript.py
sopra), allora __name__
è invece impostato alla stringa "__main__"
. Quindi, puoi testare se il tuo script viene eseguito direttamente o se viene importato da qualcos'altro testando
if __name__ == "__main__":
...
Se il vostro script viene importato in un altro modulo, le sue varie definizioni di funzioni e classi verranno importate e il suo codice di primo livello verrà eseguito, ma il codice nel corpo della clausola if
di cui sopra non verrà eseguito poiché la condizione non è soddisfatta. Come esempio di base, considerate i seguenti due script:
# 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 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")
Ora, se invocate l'interprete come
python one.py
L'output sarà
top-level in one.py
one.py is being run directly
Se invece si esegue two.py
:
python two.py
Si ottiene
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
Così, quando il modulo one
viene caricato, il suo __name__
è uguale a "one"
invece di "__main__"
.
Se name == "main"è la parte che viene eseguita quando lo script viene eseguito da (diciamo) la linea di comando usando un comando come
python myscript.py`.