[Python] Que fait si __name__ == "__main__": faire?


Answers

Lorsque votre script est exécuté en le passant en tant que commande à l'interpréteur Python,

python myscript.py

tout le code qui se trouve au niveau d'indentation 0 est exécuté. Les fonctions et les classes définies sont bien définies, mais aucun de leur code n'est exécuté. Contrairement à d'autres langages, il n'y a pas de fonction main() qui s'exécute automatiquement - la fonction main() est implicitement tout le code au plus haut niveau.

Dans ce cas, le code de niveau supérieur est un bloc if . __name__ est une variable intégrée qui évalue le nom du module courant. Cependant, si un module est exécuté directement (comme dans myscript.py ci-dessus), alors __name__ est mis à la place de la chaîne "__main__" . Ainsi, vous pouvez tester si votre script est exécuté directement ou importé par autre chose 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 niveau supérieur sera exécuté, mais le code dans le corps de la clause if ci-dessus ne sera pas exécuté comme condition n'est pas rencontré. À titre d'exemple, 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 appelez l'interpréteur comme

python one.py

La sortie sera

top-level in one.py
one.py is being run directly

Si vous exécutez two.py 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, quand le module one est chargé, son __name__ est égal à "one" au lieu de "__main__" .

Question

Que fait le if __name__ == "__main__": faire?

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



Que fait le if __name__ == "__main__": faire?

Pour décrire les bases:

  • La variable globale, __name__ , dans le module qui est le point d'entrée de votre programme, est '__main__' . Sinon, c'est le nom par lequel vous importez le module.

  • Ainsi, le code sous le bloc if ne s'exécutera que si le module est le point d'entrée de votre programme.

  • Il permet au code du module d'être importable par d'autres modules, sans exécuter le bloc de code sous import.

Pourquoi avons nous besoin de ça?

Développer et tester votre code

Supposons que vous écrivez un script Python conçu pour être utilisé comme module:

def do_important():
    """This function does something very important"""

Vous pourriez tester le module en ajoutant cet appel de la fonction en bas:

do_important()

et l'exécuter (sur une invite de commande) avec quelque chose comme:

~$ python important.py

Le problème

Cependant, si vous voulez importer le module dans un autre script:

import important

Lors de l'importation, la fonction do_important serait appelée, donc vous commenteriez probablement votre appel de fonction, do_important() , en bas.

# do_important() # I must remember to uncomment to execute this!

Et puis vous devrez vous rappeler si vous avez ou non commenté votre appel de fonction de test. Et cette complexité supplémentaire signifie que vous risquez d'oublier, ce qui rend votre processus de développement plus difficile.

Une meilleure façon

La variable __name__ pointe vers l'espace de noms où se trouve l'interpréteur Python pour le moment.

Dans un module importé, c'est le nom de ce module.

Mais à l'intérieur du module principal (ou d'une session Python interactive, c'est-à-dire Read, Eval, Print Loop ou REPL de l'interpréteur), vous exécutez tout depuis son "__main__" .

Donc, si vous vérifiez avant d'exécuter:

if __name__ == "__main__":
    do_important()

Avec ce qui précède, votre code n'exécutera que lorsque vous l'exécutez en tant que module principal (ou l'appelez intentionnellement à partir d'un autre script).

Une façon encore meilleure

Cependant, il existe un moyen Pythonien de s'améliorer.

Et si nous voulons exécuter ce processus métier depuis l'extérieur du module?

Si nous mettons le code que nous voulons exercer au fur et à mesure que nous développons et testons une fonction comme celle-ci, nous vérifions immédiatement '__main__' immédiatement après:

def main():
    """business logic for when running this module as the primary one!"""
    setup()
    foo = do_important()
    bar = do_even_more_important(foo)
    for baz in bar:
        do_super_important(baz)
    teardown()

# Here's our payoff idiom!
if __name__ == '__main__':
    main()

Nous avons maintenant une fonction finale pour la fin de notre module qui fonctionnera si nous exécutons le module en tant que module principal.

Il permettra au module et à ses fonctions et classes d'être importés dans d'autres scripts sans exécuter la fonction main , et permettra également au module (et à ses fonctions et classes) d'être appelé lors de l'exécution à partir d'un autre module '__main__'

import important
important.main()

Cet idiome peut également être trouvé dans la documentation Python dans une explication du module __main__ . Ce texte dit:

Ce module représente la portée (sinon anonyme) dans laquelle s'exécute le programme principal de l'interpréteur - les commandes lues soit à partir d'une entrée standard, soit à partir d'un fichier de script, soit à partir d'une invite interactive. C'est dans cet environnement que la strophe "script conditionnel" idiomatique provoque l'exécution d'un script:

if __name__ == '__main__':
    main()



si nom == ' main ':

Nous voyons si __name__ == '__main__' : assez souvent.

Il vérifie si un module est importé ou non.

En d'autres termes, le code dans le bloc if sera exécuté uniquement lorsque le code s'exécute directement. Ici signifie directly not imported .

Voyons ce qu'il fait en utilisant un code simple qui imprime le nom de la modue:

# test.py
def test():
   print('test module name=%s' %(__name__))

if __name__ == '__main__':
   print('call test()')
   test()

Si nous python test.py le code directement via python test.py , le nom du module est __main__ :

call test()
test module name=__main__



Lorsque vous exécutez interactivement Python, la variable locale __name__ est affectée à la valeur __main__ . De même, lorsque vous exécutez un module Python à partir de la ligne de commande, plutôt que de l'importer dans un autre module, son attribut __name__ se voit attribuer une valeur de __main__ , plutôt que le nom réel du module. De cette façon, les modules peuvent regarder leur propre valeur __name__ pour déterminer eux-mêmes comment ils sont utilisés, que ce soit en tant que support pour un autre programme ou comme application principale exécutée à partir de la ligne de commande. Ainsi, l'idiome suivant est assez commun dans les modules Python:

if __name__ == '__main__':
    # Do something appropriate here, like calling a
    # main() function defined elsewhere in this module.
    main()
else:
    # Do nothing. This module has been imported by another
    # module that wants to make use of the functions,
    # classes and other useful bits it has defined.



if __name__ == "__main__": est fondamentalement un environnement de script de niveau supérieur, il spécifie l'interpréteur ('J'ai la priorité la plus haute à exécuter en premier').

'__main__' est le nom de l'étendue dans laquelle le code de niveau supérieur s'exécute. Le __name__ un module est égal à '__main__' lorsqu'il est lu depuis une entrée standard, un script ou une invite interactive.

if __name__ == "__main__":
    # execute only if run as a script
    main()



if __name__ == "__main__":
    main()

Vérifie si l'attribut __name__ du script python est "__main__" . En d'autres termes, si le programme lui-même est exécuté, l'attribut sera __main__ , donc le programme sera exécuté (dans ce cas, la fonction main() ).

Cependant, si votre script python est utilisé par un module, tout code en dehors de l'instruction if sera exécuté, donc if \__name__ == "\__main__" est utilisé juste pour vérifier si le programme est utilisé comme module ou non, et décide donc d'exécuter le code.




Vous pouvez rendre le fichier utilisable en tant que script ainsi qu'un module importable .

fibo.py (un module nommé fibo )

# Other modules can IMPORT this MODULE to use the function fib
def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end=' ')
        a, b = b, a+b
    print()

# This allows the file to be used as a SCRIPT
if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

Référence: https://docs.python.org/3.5/tutorial/modules.html




Avant d'expliquer quoi que ce soit à propos de if __name__ == '__main__' il est important de comprendre ce que __name__ est et ce qu'il fait.

Qu'est-ce que __name__ ?

__name__ est un DunderAlias ​​- peut être considéré comme une variable globale (accessible depuis les modules) et fonctionne de la même manière que global .

C'est une chaîne (globale comme mentionné ci-dessus) comme indiqué par le type(__name__) (cédant <class 'str'> ), et est une norme intégrée pour les versions Python 3 et Python 2 .

Où:

Il peut non seulement être utilisé dans les scripts, mais peut également être trouvé dans l'interpréteur et dans les modules / packages.

Interprète:

>>> print(__name__)
__main__
>>>

Scénario:

test_file.py :

print(__name__)

Résultant en __main__

Module ou paquet:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

Résultant dans un somefile

Notez que lorsqu'il est utilisé dans un package ou un module, __name__ prend le nom du fichier. Le chemin du module ou du chemin du paquet n'est pas donné, mais possède son propre DunderAlias __file__ , qui le permet.

Vous devriez voir que, où __name__ , où il s'agit du fichier principal (ou du programme) renverra toujours __main__ , et s'il s'agit d'un module / package, ou de tout autre script Python, retournera le nom du fichier d'où il vient.

Entraine toi:

Être une variable signifie que sa valeur peut être écrasée ("peut" ne signifie pas "devrait"), l'écrasement de la valeur de __name__ entraînera un manque de lisibilité. Alors ne le faites pas, pour une raison quelconque. Si vous avez besoin d'une variable, définissez une nouvelle variable.

Il est toujours supposé que la valeur de __name__ soit __main__ ou le nom du fichier. Une fois de plus, la modification de cette valeur par défaut entraînera plus de confusion et fera du bien, causant des problèmes plus loin dans la ligne.

Exemple:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

Il est considéré comme une bonne pratique en général d'inclure le if __name__ == '__main__' dans les scripts.

Maintenant, pour répondre if __name__ == '__main__' :

Maintenant nous savons que le comportement de __name__ devient plus clair:

Un if est une instruction de contrôle de flux qui contient le bloc de code qui s'exécutera si la valeur donnée est vraie. Nous avons vu que __name__ peut prendre soit __main__ soit le nom du fichier dont il a été importé.

Cela signifie que si __name__ est égal à __main__ alors le fichier doit être le fichier principal et doit être en cours d'exécution (ou c'est l'interpréteur), pas un module ou un paquet importé dans le script.

Si en effet __name__ prend la valeur de __main__ alors tout ce qui est dans ce bloc de code sera exécuté.

Cela nous indique que si le fichier en cours d'exécution est le fichier principal (ou que vous exécutez directement à partir de l'interpréteur), cette condition doit s'exécuter. Si c'est un paquet, alors il ne devrait pas, et la valeur ne sera pas __main__ .

Modules:

__name__ peut également être utilisé dans les modules pour définir le nom d'un module

Variantes

Il est également possible de faire d'autres choses, moins courantes mais utiles avec __name__ , certaines que je montrerai ici:

Exécuter seulement si le fichier est un module ou un paquet:

if __name__ != '__main__':
    # Do some useful things 

En cours d'exécution une condition si le fichier est le principal et un autre si ce n'est pas:

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

Vous pouvez également l'utiliser pour fournir des fonctions / utilitaires d'aide exécutables sur des packages et des modules sans l'utilisation complexe de bibliothèques.

Il permet également d'exécuter des modules à partir de la ligne de commande en tant que scripts principaux, ce qui peut également être très utile.




Que fait if __name__ == "__main__": faire?

__name__ est une variable globale (en Python, global signifie au niveau du module ) qui existe dans tous les espaces de noms. C'est typiquement le nom du module (comme un type de str ).

Comme seul cas particulier, cependant, quel que soit le processus Python exécuté, comme dans mycode.py:

python mycode.py

l'espace de noms global anonyme est assigné la valeur de '__main__' à son __name__ .

Ainsi, y compris les dernières lignes

if __name__ == '__main__':
    main()
  • à la fin de votre script mycode.py,
  • quand c'est le module primaire, point d'entrée qui est exécuté par un processus Python,

provoquera l'exécution de la fonction main votre script.

Un autre avantage de l'utilisation de cette construction: vous pouvez également importer votre code en tant que module dans un autre script, puis exécuter la fonction principale si et quand votre programme décide:

import mycode
# ... any amount of other code
mycode.main()



Beaucoup de différentes prises ici sur la mécanique du code en question, le "Comment", mais pour moi rien de tout cela n'a de sens jusqu'à ce que j'ai compris le "Pourquoi". Cela devrait être particulièrement utile pour les nouveaux programmeurs.

Prenez le fichier "ab.py":

def a():
    print('A function in ab file');
a()

et un deuxième fichier "xy.py":

import ab
def main():
    print('main function: this is where the action is')
def x(): 
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

Que fait ce code?

Lorsque vous exécutez xy.py , vous import ab . L'instruction import exécute le module immédiatement lors de l'importation, donc les opérations de ab sont exécutées avant le reste des xy . Une fois fini avec ab , il continue avec xy .

L'interpréteur garde la trace des scripts en cours d'exécution avec __name__ . Lorsque vous exécutez un script, quel que soit le nom que vous lui avez donné, l'interpréteur l'appelle "__main__" , ce qui en fait le maître ou le script "home" renvoyé après l'exécution d'un script externe. Tout autre script appelé à partir de ce script "__main__" se voit attribuer son nom de fichier comme __name__ (par exemple, __name__ == "ab.py" ). Par conséquent, la ligne if __name__ == "__main__": est le test de l'interpréteur pour déterminer s'il interprète / analyse le script "home" qui a été initialement exécuté, ou s'il est temporairement en train de lire un autre script (externe). Cela donne au programmeur une flexibilité pour que le script se comporte différemment s'il est exécuté directement par rapport à un appel externe.

Passons en revue le code ci-dessus pour comprendre ce qui se passe, en nous concentrant d'abord sur les lignes non indentifiées et l'ordre dans lequel elles apparaissent dans les scripts. Rappelez-vous que les blocs function - ou def - ne font rien par eux-mêmes jusqu'à ce qu'ils soient appelés. Ce que l'interprète pourrait dire s'il marmonnait à lui-même:

  • Ouvrez xy.py en tant que fichier "home". appelez-le "__main__" dans la variable __name__ .
  • Importer et ouvrir le fichier avec __name__ == "ab.py" .
  • Oh, une fonction. Je m'en souviendrai.
  • Ok, la fonction a() ; Je viens d'apprendre ça. Impression ' Une fonction dans un fichier ab '.
  • Fin de fichier; retour à "__main__" !
  • Oh, une fonction. Je m'en souviendrai.
  • Un autre.
  • Fonction x() ; ok, impression ' tâche périphérique: pourrait être utile dans d'autres projets '.
  • Qu'est-ce que c'est ça? Une instruction if . Eh bien, la condition a été remplie (la variable __name__ a été définie sur "__main__" ), donc je vais entrer la fonction main() et imprimer la fonction principale: c'est là que se trouve l'action '.

Les deux lignes du bas signifient: "S'il s'agit du script main ou 'home', exécutez la fonction appelée main() ". C'est pourquoi vous verrez un bloc def main(): block up, qui contient le flux principal de la fonctionnalité du script.

Pourquoi implémenter cela?

Rappelez-vous ce que j'ai dit plus tôt à propos des déclarations d'importation? Lorsque vous importez un module, il ne le «reconnaît» pas et attend des instructions supplémentaires: il exécute en fait toutes les opérations exécutables contenues dans le script. Ainsi, mettre la viande de votre script dans la fonction main() en quarantaine, en la mettant dans l'isolement afin qu'elle ne soit pas immédiatement exécutée lorsqu'elle est importée par un autre script.

Encore une fois, il y aura des exceptions, mais la pratique courante est que main() n'est généralement pas appelé de l'extérieur. Vous vous demandez peut-être encore une chose: si nous n'appelons pas main() , pourquoi appelons-nous le script? C'est parce que beaucoup de gens structurent leurs scripts avec des fonctions autonomes qui sont construites pour être exécutées indépendamment du reste du code dans le fichier. Ils sont ensuite appelés plus tard ailleurs dans le corps du script. Ce qui m'amène à ceci:

Mais le code fonctionne sans

Oui c'est vrai. Ces fonctions séparées peuvent être appelées à partir d'un script en ligne qui n'est pas contenu dans une fonction main() . Si vous êtes habitué (comme je le suis, dans mes premières étapes de programmation) à construire des scripts en ligne qui font exactement ce dont vous avez besoin, et vous essaierez de le comprendre à nouveau si jamais vous avez encore besoin de cette opération. eh bien, vous n'êtes pas habitué à ce type de structure interne à votre code, car c'est plus compliqué à construire et ce n'est pas aussi intuitif à lire. Mais c'est un script qui ne peut probablement pas avoir ses fonctions appelées de manière externe, car si c'était le cas, il commencerait immédiatement à calculer et assigner des variables. Et il y a des chances que si vous essayez de réutiliser une fonction, votre nouveau script soit assez proche de l'ancien pour qu'il y ait des variables en conflit.

En divisant les fonctions indépendantes, vous pouvez réutiliser votre travail précédent en les appelant dans un autre script. Par exemple, "example.py" peut importer "xy.py" et appeler x() , en utilisant la fonction "x" de "xy.py". (Il est peut-être en train de mettre en majuscule le troisième mot d'une chaîne de caractères donnée, de créer un tableau numérique à partir d'une liste de nombres et de les équerrer, ou de détourner une surface 3D.

[En aparté, ce fil contient une réponse par @kindall qui m'a finalement aidé à comprendre - le pourquoi, pas le comment. Malheureusement, il a été marqué comme une copie de celui-ci , ce qui est une erreur selon moi.]




Il existe un certain nombre de variables que le système (interpréteur Python) fournit pour les fichiers source (modules). Vous pouvez obtenir leurs valeurs à tout moment, alors concentrons-nous sur la variable / l'attribut __name__ :

Lorsque Python charge un fichier de code source, il exécute tout le code qui s'y trouve. (Notez qu'il n'appelle pas toutes les méthodes et fonctions définies dans le fichier, mais qu'il les définit.)

Avant que l'interpréteur n'exécute le fichier de code source, il définit quelques variables spéciales pour ce fichier; __name__ est l'une de ces variables spéciales que Python définit automatiquement pour chaque fichier de code source.

Si Python charge ce fichier de code source en tant que programme principal (c'est-à-dire le fichier que vous exécutez), alors il définit la variable spéciale __name__ pour que ce fichier ait une valeur "__main__" .

Si cela est importé d'un autre module, __name__ sera défini sur le nom de ce module.

Donc, dans votre exemple en partie:

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

signifie que le bloc de code:

lock = thread.allocate_lock()
thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

sera exécuté uniquement lorsque vous exécutez le module directement; le bloc de code ne s'exécutera pas si un autre module l'appelle / l'importe car la valeur de __name__ ne sera pas égale à " main " dans cette instance particulière.

J'espère que cela aide.




Links