__main__
— Environnement d'exécution principal¶
En Python, le nom __main__
a une fonction particulière. Il intervient dans deux cas :
c'est le nom de l'environnement d'exécution principal, ce qui donne lieu au test courant
__name__ == '__main__'
;c'est aussi le nom du fichier
__main__.py
dans les paquets Python.
Les deux sont liés aux modules Python, à la manière de s'en servir en tant qu'utilisateur et à la manière dont ils interagissent entre eux. Cette page contient des détails sur les modules Python. Si vous ne les avez jamais utilisés, commencez par la section qui leur est consacrée dans le tutoriel : Modules.
__name__ == '__main__'
¶
Lorsqu'un module ou un paquet Python est importé, son attribut __name__
est défini à son nom, qui est la plupart du temps le nom du fichier qui le contient sans l'extension .py
:
>>> import configparser
>>> configparser.__name__
'configparser'
Si le fichier fait partie d'un paquet, __name__
donne tout le chemin d'accès :
>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'
En revanche, si le module est exécuté dans l'environnement d'exécution principal, la variable __name__
vaut '__main__'
.
Qu'est-ce que l'« environnement d'exécution principal » ?¶
L'environnement principal a pour nom __main__
. Il s'agit du premier module Python dont l'exécution a été demandée par l'utilisateur final. On le qualifie de principal car c'est lui qui importe tous les autres modules nécessités par le programme. On l'appelle parfois le point d'entrée de l'application.
L'environnement principal peut prendre diverses formes :
l'environnement d'une invite de commande interactive :
>>> __name__ '__main__'
le module passé directement en tant que fichier à la commande de l'interpréteur Python :
$ python3 helloworld.py Hello, world!
le module ou paquet passé à l'interpréteur avec l'option
-m
:$ python3 -m tarfile usage: tarfile.py [-h] [-v] (...)
le code lu par l'interpréteur depuis l'entrée standard :
$ echo "import this" | python3 The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
le code passé à l'interpréteur avec l'option
-c
:$ python3 -c "import this" The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
Dans chacun de ces cas, l'attribut __name__
du module principal est mis à '__main__'
.
Un module peut donc savoir s'il est exécuté dans l'environnement principal en vérifiant son __name__
, ce qui permet typiquement d'exécuter du code lorsque le module est initialisé d'une manière autre que l'importation :
if __name__ == '__main__':
# Execute when the module is not initialized from an import statement.
...
Voir aussi
Pour plus de détails sur la manière dont __name__
est défini dans les divers cas, voir la section Modules dans le tutoriel.
Utilisation idiomatique¶
Il arrive qu'un module contienne du code qui ne doit s'exécuter que lorsque le module est utilisé comme script. On peut penser à l'analyse des arguments passés en ligne de commande, ou bien à la lecture de l'entrée standard. Il ne faudrait pas que ces opérations soient effectuées lorsque le module est importé depuis un autre module, comme pour les tests.
C'est dans ces situations que sert la construction if __name__ == '__main__'
. Le code mis à l'intérieur du bloc n'est exécuté que si le module est dans l'environnement principal.
Il vaut mieux mettre aussi peu de code que possible sous le if __name__ == '__main__'
pour garder le code clair et limiter les risques d'erreur. La plupart du temps, on écrit une fonction main
qui contient tout le code spécifique à l'utilisation comme script :
# echo.py
import shlex
import sys
def echo(phrase: str) -> None:
"""A dummy wrapper around print."""
# for demonstration purposes, you can imagine that there is some
# valuable and reusable logic inside this function
print(phrase)
def main() -> int:
"""Echo the input arguments to standard output"""
phrase = shlex.join(sys.argv)
echo(phrase)
return 0
if __name__ == '__main__':
sys.exit(main()) # next section explains the use of sys.exit
Si, dans le module ci-dessus, le code de main
était placé directement dans le if __name__ == '__main__'
, la variable phrase
serait globale, et d'autres fonctions pourraient s'en servir par erreur à la place d'une variable locale. Encapsuler le code dans la fonction main
évite cet ennui.
De plus, la fonction echo
est elle-même séparée du reste, et on peut l'importer dans un autre module. Le fait d'importer echo.py
définit les fonctions main
et echo
, mais n'en appelle aucune, puisque __name__ != '__main__'
.
Considérations liées à l'empaquetage¶
Les fonctions main
servent souvent à créer des outils qui s'exécutent en ligne de commande. Les scripts sont ajoutés au système à l'aide de points d'entrée, qui demandent à pip de créer un exécutable. Il le fait en insérant un appel à la fonction à l'intérieur d'un modèle prédéfini où la valeur qu'elle renvoie est passée directement à sys.exit()
:
sys.exit(main())
Puisque l'appel de main
est encapsulé dans sys.exit()
, main
doit renvoyer une valeur qui convienne comme argument à sys.exit()
, par exemple un code de retour sous forme d'entier. La valeur None
est également acceptée, et c'est d'ailleurs celle que renvoie la fonction si elle se termine sans rencontrer d'instruction return
.
Il est utile de se conformer à cette convention. De cette manière, le module se comporte de la même manière s'il est distribué comme script à l'aide des points d'entrée que lorsqu'il est exécuté directement (avec python3 echo.py
).
En particulier, mieux vaut éviter de renvoyer une chaîne de caractères depuis la fonction main
. En effet, si sys.exit()
reçoit une chaîne, elle l'interprète comme un message d'erreur, qu'elle affiche sur sys.stderr
avant de terminer le programme avec le code de retour 1 (erreur). L'exemple de echo.py
ci-dessus montre la pratique recommandée.
Voir aussi
Le guide de l'empaquetage en Python (en anglais) contient plusieurs tutoriels et documents de référence autour de la distribution et de l'installation de paquets Python avec des outils modernes.
Le fichier __main__.py
dans les paquets Python¶
Si vous n'êtes pas familier des paquets Python, lisez Les paquets dans le tutoriel. Un fichier __main__.py
permet à un paquet de définir une interface en ligne de commande. Prenons pour exemple un paquet nommé bandclass :
bandclass
├── __init__.py
├── __main__.py
└── student.py
Le fichier __main__.py
qu'il contient s'exécute lorsque le paquet est appelé depuis la ligne de commande avec l'option -m
de l'interpréteur, comme ceci :
$ python3 -m bandclass
Cette commande lance l'exécution de __main__.py
. Il vous appartient, en tant que concepteur du paquet, de déterminer ce qu'elle doit faire. Dans notre exemple, elle pourrait rechercher un étudiant dans une base de données :
# bandclass/__main__.py
import sys
from .student import search_students
student_name = sys.argv[2] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')
Remarquez l'importation from .student import search_students
. Le point avant student
sert à rendre le chemin student
relatif à la position du module qui l'importe. Pour plus d'informations, voir Références internes dans un paquet dans la section Modules du tutoriel.
Utilisation idiomatique¶
En général, on ne met pas le code de __main__.py
dans un bloc if __name__ == '__main__'
. Il vaut mieux définir toutes les fonctions utiles dans d'autres modules et réduire la taille du fichier __main__.py
au minimum. Il est alors plus facile de tester et réutiliser ces autres modules.
Cependant, un if __name__ == '__main__'
, s'il est présent dans le __main__.py
, fonctionne correctement. En effet, si __main__.py
est importé depuis autre module, son attribut __name__
contient, avant __main__
, le nom du paquet dont il fait partie :
>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'
Malgré tout, cela ne fonctionne pas pour les fichiers __main__.py
à la racine d'une archive ZIP. Aussi est-il préférable d'écrire des __main__.py
dans le style minimal de celui de venv
mentionné ci-dessus.
Voir aussi
See venv
for an example of a package with a minimal __main__.py
in the standard library. It doesn't contain a if __name__ == '__main__'
block. You can invoke it with python -m venv [directory]
.
La documentation du module runpy
fournit une description complète de l'option -m
de l'interpréteur.
Le module zipapp
exécute des applications emballées dans une archive ZIP. Dans ce cas, l'interpréteur recherche un fichier __main__.py
à la racine de l'archive.
import __main__
¶
Quel que soit le module principal d'un programme, les autres modules peuvent accéder à l'espace de nommage dans lequel il s'exécute en important le module spécial __main__
. Celui-ci ne correspond pas forcément à un fichier __main__.py
. Il s'agit simplement du module qui a reçu le nom '__main__'
.
Voici un exemple d'utilisation du module __main__
:
# namely.py
import __main__
def did_user_define_their_name():
return 'my_name' in dir(__main__)
def print_user_name():
if not did_user_define_their_name():
raise ValueError('Define the variable `my_name`!')
if '__file__' in dir(__main__):
print(__main__.my_name, "found in file", __main__.__file__)
else:
print(__main__.my_name)
Ce code s'utilise comme ceci :
# start.py
import sys
from namely import print_user_name
# my_name = "Dinsdale"
def main():
try:
print_user_name()
except ValueError as ve:
return str(ve)
if __name__ == "__main__":
sys.exit(main())
Le programme ci-dessus donne la sortie :
$ python3 start.py
Define the variable `my_name`!
Son code de retour est 1, ce qui signifie une erreur. En supprimant la marque de commentaire en début de ligne my_name = "Dinsdale"
, le programme est corrigé, et renvoie au système le code 0 car il n'y a plus d'erreur :
$ python3 start.py
Dinsdale found in file /path/to/start.py
On pourrait s'attendre à un problème au moment de l'importation de __main__
: cela ne provoque-t-il pas l'exécution anticipée du code de script sous if __name__ == '__main__'
dans le module principal start
?
En fait, le déroulement de l'exécution est le suivant : au lancement de l'interpréteur, un module __main__
initialement vide est inséré dans sys.modules
. Il se remplit au fur et à mesure de l'exécution du code principal. Dans notre exemple, le module principal est start
, qui s'exécute ligne par ligne et en vient à importer namely
. Or namely
, à son tour, importe __main__
, c'est-à-dire en fait start
. On a donc une importation cyclique. Puisque le module __main__
est déjà présent dans sys.modules
, bien qu'encore incomplet, il est directement passé à namely
sans réimportation. La section Cas particulier de __main__ dans le document de référence du système d'importation explique plus avant ce fonctionnement.
L'interpréteur interactif est un autre environnement d'exécution principal possible. Toute variable qui y est définie appartient à l'espace de nommage __main__
:
>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky
Dans ce cas, il n'y a pas de variable __file__
, puisque cela n'a pas de sens dans le mode interactif.
Le module __main__
est notamment employé dans les implémentations de pdb
et rlcompleter
.