Qu'est-ce que __main__.py?

326

À quoi sert le __main__.pyfichier, quel type de code dois-je y mettre et quand dois-je en avoir un?

Monika Sulik
la source

Réponses:

320

Souvent, un programme Python est exécuté en nommant un fichier .py sur la ligne de commande:

$ python my_program.py

Vous pouvez également créer un répertoire ou un fichier zip plein de code et inclure un fichier __main__.py. Ensuite, vous pouvez simplement nommer le répertoire ou le fichier zip sur la ligne de commande, et il exécute __main__.pyautomatiquement:

$ python my_program_dir
$ python my_program.zip
# Or, if the program is accessible as a module
$ python -m my_program

Vous devrez décider par vous-même si votre application pourrait bénéficier d'une telle exécution.


Notez qu'un __main__ module ne provient généralement pas d'un __main__.pyfichier. C'est possible, mais ce n'est généralement pas le cas. Lorsque vous exécutez un script comme python my_program.py, le script s'exécutera en tant que __main__module au lieu du my_programmodule. Cela se produit également pour les modules exécutés en tant que python -m my_moduleou de plusieurs autres manières.

Si vous avez vu le nom __main__dans un message d'erreur, cela ne signifie pas nécessairement que vous devriez rechercher un __main__.pyfichier.

Ned Batchelder
la source
22
J'ai trouvé python -m program_diret python program_dirun peu différent: ce dernier ne tourne jamais __init__.pydans le répertoire (s'il y en a un).
brk
5
@brk: Cela ne semble pas être le cas actuellement. J'ai juste essayé python3 program_diret ça a fonctionné __init__.py.
mk12
@ mk12 Je viens de l'essayer, je peux confirmer les conclusions de @ brk: python3 dirs'exécute __main__.pymais pas __init__.py, tandis que python3 -m dirs'exécute les deux.
Marcello Romani
1
@ mk12 Vous aviez probablement un code dans __main__.pylequel a déclenché l'importation de__init__.py
wim
100

À quoi sert le __main__.pyfichier?

Lors de la création d'un module Python, il est courant que le module exécute certaines fonctionnalités (généralement contenues dans une mainfonction) lorsqu'il est exécuté comme point d'entrée du programme. Cela se fait généralement avec l'idiome commun suivant placé au bas de la plupart des fichiers Python:

if __name__ == '__main__':
    # execute only if run as the entry point into the program
    main()

Vous pouvez obtenir la même sémantique pour un package Python avec __main__.py. Il s'agit d'une invite de shell Linux $, si vous n'avez pas Bash (ou un autre shell Posix) sous Windows, créez simplement ces fichiers demo/__<init/main>__.pyavec un contenu entre les EOFs:

$ mkdir demo
$ cat > demo/__init__.py << EOF
print('demo/__init__.py executed')
def main():
    print('main executed')
EOF
$ cat > demo/__main__.py << EOF
print('demo/__main__.py executed')
from __init__ import main
main()
EOF

(Dans un shell Posix / Bash, vous pouvez faire ce qui précède sans le << EOFs et la fin de EOFs en entrant Ctrl+ D, le caractère de fin de fichier, à la fin de chaque commande cat)

Et maintenant:

$ python demo
demo/__main__.py executed
demo/__init__.py executed
main executed

Vous pouvez dériver cela de la documentation. La documentation dit:

__main__ - Environnement de script de niveau supérieur

'__main__'est le nom de la portée dans laquelle le code de niveau supérieur s'exécute. Un module __name__est défini égal à '__main__'lorsqu'il est lu à partir d'une entrée standard, d'un script ou d'une invite interactive.

Un module peut découvrir s'il s'exécute ou non dans la portée principale en vérifiant le sien __name__, ce qui permet à un idiome commun d'exécuter conditionnellement du code dans un module lorsqu'il est exécuté en tant que script ou avec python -mmais pas lorsqu'il est importé:

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

Pour un package, le même effet peut être obtenu en incluant un __main__.pymodule, dont le contenu sera exécuté lors de l'exécution du module -m.

Zippé

Vous pouvez également empaqueter cela dans un seul fichier et l'exécuter à partir de la ligne de commande comme ceci - mais notez que les paquets zippés ne peuvent pas exécuter des sous-paquets ou des sous-modules comme point d'entrée:

$ python -m zipfile -c demo.zip demo/*
$ python demo.zip
demo/__main__.py executed
demo/__init__.py executed
main() executed
Aaron Hall
la source
31

__main__.pyest utilisé pour les programmes python dans les fichiers zip. Le __main__.pyfichier sera exécuté lors de l'exécution du fichier zip. Par exemple, si le fichier zip était en tant que tel:

test.zip
     __main__.py

et le contenu de __main__.pyétait

import sys
print "hello %s" % sys.argv[1]

Ensuite, si nous python test.zip worlddevions courir, nous sortirions hello world.

Le __main__.pyfichier s'exécute donc lorsque python est appelé sur un fichier zip.

Poivrons bleus
la source
23

Vous créez __main__.pydans yourpackagepour le rendre exécutable comme:

$ python -m yourpackage
anatoly techtonik
la source
1
-mfonctionne si seul le programme est accessible en tant que module, sinon vous pouvez utiliser python <yourpackage>REMARQUE: sans -moption
Benyamin Jafari
1
@BenyaminJafari il n'est pas possible d'écrire un programme Python en ligne de commande qui n'est pas accessible en tant que module . Peut-être que vous vouliez dire package?
anatoly techtonik
1
lorsque nous créons un package Python qui contient le fichier .py principal , son exécution ne python -m <yourproject>fonctionne pas, -mest une option redondante, mais python <yourpackage>fonctionne bien.
Benyamin Jafari
@BenyaminJafari L'indicateur -m fait une différence dans certains cas. Exécuter à partir du répertoire aet assumer le script a/b/c/__main__.py... python -m b.cs'exécutera à partir du répertoire aet les importations du script principal seront relatives à a. Mais python b/cs'exécutera à partir de la portée d'importation de dir cet donc toute importation comme dans le script principal comme import b.déchouera.
MikeCPT
14

Si votre script est un répertoire ou un fichier ZIP plutôt qu'un fichier python unique, __main__.pyil sera exécuté lorsque le "script" sera passé en argument à l'interpréteur python.

Wooble
la source