Que fait le 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))
Lorsque l'interpréteur Python lit un fichier source, il fait deux choses :
il définit quelques variables spéciales comme __name__
, et ensuite
il exécute tout le code trouvé dans le fichier.
Voyons comment cela fonctionne et comment cela se rapporte à votre question sur les vérifications __name__
que nous voyons toujours dans les scripts Python.
Utilisons un exemple de code légèrement différent pour explorer le fonctionnement des importations et des scripts. Supposons que ce qui suit se trouve dans un fichier appelé 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")
Lorsque l'interpréteur Python lit un fichier source, il définit d'abord quelques variables spéciales. Dans ce cas, nous nous intéressons à la variable __name__
.
Lorsque votre module est le programme principal
Si vous exécutez votre module (le fichier source) en tant que programme principal, par ex.
python foo.py
l'interpréteur assignera la chaîne de caractères codée en dur "__main__"
à la variable __name__
, soit
# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__"
Quand votre module est importé par un autre
D'un autre côté, supposons qu'un autre module soit le programme principal et qu'il importe votre module. Cela signifie qu'il y a une déclaration comme celle-ci dans le programme principal, ou dans un autre module que le programme principal importe :
# Suppose this is in some other main program.
import foo
Dans ce cas, l'interpréteur regardera le nom de fichier de votre module, foo.py
, enlèvera le .py
, et assignera cette chaîne à la variable __name__
de votre module, soit
# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"
Après avoir configuré les variables spéciales, l'interpréteur exécute tout le code du module, une instruction à la fois. Il se peut que vous souhaitiez ouvrir une autre fenêtre du côté de l'échantillon de code afin de pouvoir suivre cette explication.
Toujours
Il imprime la chaîne "before import" (sans les guillemets).
Elle charge le module math
et l'assigne à une variable appelée math
. Cela revient à remplacer import math
par ce qui suit (notez que __import__
est une fonction de bas niveau en Python qui prend une chaîne de caractères et déclenche l'importation réelle) :
# Trouver et charger un module à partir de son nom en chaîne, "math",
# puis l'assigne à une variable locale appelée math.
math = __import__("math")
Il imprime la chaîne "avant la fonctionA"
.
Il exécute le bloc def
, en créant un objet fonction, puis en assignant cet objet fonction à une variable appelée functionA
.
Il imprime la chaîne "before functionB"
.
Il exécute le deuxième bloc def
, en créant un autre objet fonction, puis en l'assignant à une variable appelée functionB
.
Elle imprime la chaîne "before __name__ guard"
.
Uniquement lorsque votre module est le programme principal
__name__
a bien été défini comme "__main__"
et il appelle les deux fonctions, en imprimant les chaînes "Function A"
et "Function B 10.0"
.Uniquement lorsque votre module est importé par un autre
__name__
sera "foo"
, et non "__main__"
, et il sautera le corps de l'instruction if
.Toujours
"after __name__ guard"
dans les deux situations.***Il n'y a pas de problème.
En résumé, voici ce qui serait imprimé dans les deux cas :
# 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
Vous pouvez naturellement vous demander pourquoi quelqu'un voudrait ceci. Eh bien, parfois vous voulez écrire un fichier .py
qui peut être à la fois utilisé par d'autres programmes et/ou modules en tant que module, et qui peut aussi être exécuté en tant que programme principal lui-même. Exemples :
Votre module est une bibliothèque, mais vous voulez avoir un mode script où il exécute des tests unitaires ou une démo.
Votre module est seulement utilisé comme programme principal, mais il a quelques tests unitaires, et le cadre de test fonctionne en important des fichiers .py
comme votre script et en exécutant des fonctions de test spéciales. Vous ne voulez pas qu'il essaie d'exécuter le script juste parce qu'il importe le module.
Votre module est principalement utilisé comme programme principal, mais il fournit également une API conviviale pour les utilisateurs avancés.
Au-delà de ces exemples, il est élégant de constater que l'exécution d'un script en Python consiste simplement à configurer quelques variables magiques et à importer le script. "L'exécution du script est un effet secondaire de l'importation du module du script.
Question : Puis-je avoir plusieurs blocs de vérification __name__
? Réponse : c'est étrange de le faire, mais le langage ne vous en empêchera pas.
Supposons que ce qui suit se trouve dans foo2.py
. Que se passe-t-il si vous dites python foo2.py
sur la ligne de commande ? Pourquoi ?
# 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__
dans 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")
Lorsque votre script est exécuté en le passant comme une commande à l'interpréteur Python,
python myscript.py
tout le code qui est au niveau d'indentation 0 est exécuté. Les fonctions et les classes qui sont définies sont définies, mais aucun de leurs codes n'est exécuté. Contrairement aux autres langages, il n'y a pas de fonction main()
qui s'exécute automatiquement - la fonction main()
est implicitement tout le code du niveau supérieur.
Dans ce cas, le code de haut niveau est un bloc if
. __name__
est une variable intégrée qui correspond au nom du module courant. Cependant, si un module est exécuté directement (comme dans myscript.py
ci-dessus), alors __name__
prend la valeur de la chaîne "__main__"
. Ainsi, vous pouvez vérifier si votre script est exécuté directement ou s'il est importé par quelque chose d'autre en testant
if __name__ == "__main__":
...
Si votre script est importé dans un autre module, ses diverses définitions de fonctions et de classes seront importées et son code de haut niveau sera exécuté, mais le code dans le corps then de la clause if
ci-dessus ne sera pas exécuté car la condition n'est pas remplie. Comme exemple de base, considérons les deux scripts suivants :
# 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")
Maintenant, si vous invoquez l'interpréteur en tant que
python one.py
La sortie sera
top-level in one.py
one.py is being run directly
Si vous exécutez two.py
à la place :
python two.py
Vous obtenez
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
Ainsi, lorsque le module one
est chargé, son __name__
est égal à "one"
au lieu de "__main__"
.
if __name__ == "__main__"
est la partie qui s'exécute lorsque le script est lancé depuis (disons) la ligne de commande en utilisant une commande comme python myscript.py
.