# `__main__` — Environnement d'exécution principal

En Python, le nom `__main__` a une fonction particulière. Il intervient dans deux cas :

1. c'est le nom de l'environnement d'exécution principal, ce qui donne lieu au test courant `__name__ == '__main__'` ;

2. 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`.