Cosa fa se __name__ == "__main__":?

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

Ogni volta che l'interprete Python legge un file sorgente, fa due cose:

  • imposta alcune variabili speciali come __name__, e poi
  • esegue tutto il codice trovato nel file.

Vediamo come funziona e come si collega alla vostra domanda sui controlli di __name__ che vediamo sempre negli script Python. Esempio di codice

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

Variabili speciali

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"

Eseguire il codice del modulo

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

  1. Stampa la stringa "before import" (senza virgolette).
  2. Carica il modulo 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")
  3. Stampa la stringa "prima della funzioneA".
  4. Esegue il blocco def, creando un oggetto funzione, poi assegna tale oggetto funzione ad una variabile chiamata funzioneA.
  5. Stampa la stringa "prima della funzioneB".
  6. Esegue il secondo blocco def, creando un altro oggetto funzione, poi assegnandolo ad una variabile chiamata funzioneB.
  7. Stampa la stringa "before __name__ guard". Solo quando il vostro modulo è il programma principale
  8. Se il vostro modulo è il programma principale, allora vedrà che __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
  9. (invece) Se il vostro modulo non è il programma principale ma è stato importato da un altro, allora __name__ sarà "foo", non "__main__", e salterà il corpo della dichiarazione if. Sempre
  10. Stamperà la stringa "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

Perché funziona così?

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.

  • Il tuo modulo è usato principalmente come programma principale, ma fornisce anche un'API di facile programmazione per gli utenti avanzati. Al di là di questi esempi, è elegante che eseguire uno script in Python è solo impostare alcune variabili magiche e importare lo script. L'esecuzione dello script è un effetto collaterale dell'importazione del modulo dello script. Cibo per la mente

  • 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")
  • Ora, cercate di capire cosa succede se rimuovete il controllo __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")
  • Cosa farà questo quando viene usato come script? Quando viene importato come modulo? -- lingua: python -->
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")

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

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__".

Commentari (0)

Se name == "main"è la parte che viene eseguita quando lo script viene eseguito da (diciamo) la linea di comando usando un comando comepython myscript.py`.

Commentari (1)