Que fait si __name__ == "__main__": ?

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

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.

Exemple de code

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

Variables spéciales

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"

Exécution du code du module

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

  1. Il imprime la chaîne "before import" (sans les guillemets).

  2. 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")
  3. Il imprime la chaîne "avant la fonctionA".

  4. Il exécute le bloc def, en créant un objet fonction, puis en assignant cet objet fonction à une variable appelée functionA.

  5. Il imprime la chaîne "before functionB".

  6. Il exécute le deuxième bloc def, en créant un autre objet fonction, puis en l'assignant à une variable appelée functionB.

  7. Elle imprime la chaîne "before __name__ guard".

Uniquement lorsque votre module est le programme principal

  1. Si votre module est le programme principal, il verra que __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

  1. (à la place) Si votre module n'est pas le programme principal mais a été importé par un autre, alors __name__ sera "foo", et non "__main__", et il sautera le corps de l'instruction if.

Toujours

  1. Il imprimera la chaîne "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

Pourquoi ça marche comme ça ?

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.

Matière à réflexion

  • 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")
  • Maintenant, déterminez ce qui se passera si vous supprimez le contrôle __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")
  • Qu'est-ce que cela va faire quand on l'utilise comme un script ? Lorsqu'il est importé en tant que module ?
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")

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

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

Commentaires (0)

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.

Commentaires (1)