if __name__ == "__main__" en Python : le point d'entrée d'un script

La garde if __name__ sépare ce qu'un fichier Python doit exécuter quand on le lance de ce qu'il doit seulement mettre à disposition à l'import.
5 min de lecture
Believemy logo

Définition

Un fichier Python se lit de deux façons : lancé directement depuis un terminal, ou importé depuis un autre fichier pour n'en récupérer qu'une fonction. Le problème, c'est que Python ne fait par défaut aucune différence entre les deux, faute de fonction obligatoire nommée main comme en C ou en Java : lancer un fichier revient à exécuter ses lignes de haut en bas, définitions comprises.

C'est ce que résout la garde if __name__ == "__main__". Sa position en bas de fichier laisse croire qu'elle démarre le programme, mais elle sépare en réalité ce qui doit tourner au lancement de ce qui doit rester disponible à l'import.

PYTHON
def additionner(a, b):
    return a + b


if __name__ == "__main__":
    print(additionner(2, 3))  # ne s'exécute qu'au lancement direct

Lancé directement, ce fichier affiche 5. Importé avec import, il n'affiche rien : il met seulement sa fonction additionner à disposition. Le code est identique, seul l'usage change.


Ce que contient __name__ selon la situation

Avant d'exécuter un fichier, Python y dépose une variable spéciale, __name__. On pourrait croire qu'elle contient toujours la même chose ; c'est l'inverse qui rend le mécanisme utile. Voici ce qu'elle vaut selon la manière dont le fichier a été chargé.

SituationContenu de __name__
python outils.py"__main__"
Le même fichier importé ailleurs"outils"
python -m outils"__main__"
Saisie directe dans le REPL"__main__"
Fichier chargé par pytest"test_outils"

Le fichier lancé porte toujours le nom __main__, les autres gardent leur nom de module. La comparaison ne fait donc que demander si ce fichier est lancé ou seulement chargé.


Le problème que cela résout vraiment

Sans cette garde, importer un fichier l'exécute en entier, pas seulement ses définitions : les appels, les affichages, l'ouverture d'un fichier ou l'envoi d'une requête réseau partent avec elles, le jour où l'on importe un script pour n'en réutiliser qu'une seule fonction.

PYTHON
# nettoyage.py, sans garde
def nettoyer(chemin):
    ...


nettoyer("donnees.csv")   # part aussi à l'import, sans qu'on l'ait demandé

Le cas le plus coûteux touche multiprocessing. Sur Windows et sur macOS, ce module ne peut pas dupliquer le processus en cours comme le fait Linux : il redémarre chaque processus enfant en réimportant le fichier principal.

Attention

Sans garde, ce réimport relance la création des processus, qui eux-mêmes réimportent le fichier et recréent des processus à leur tour. Le système finit par arrêter cette avalanche de force, avec un message qui parle de freeze_support sans jamais nommer la vraie cause.


La forme à écrire, et pourquoi celle-là

Mieux vaut ne pas coller tout le programme dans la garde, mais s'en tenir à un seul appel, celui d'une fonction main qui contient le reste.

PYTHON
def main():
    config = charger_config()
    traiter(config)


if __name__ == "__main__":
    main()

La raison tient à la portée. Ce qui est écrit dans le bloc appartient au module : chaque nom devient une variable globale, modifiable par accident depuis tout le fichier. Enfermé dans une fonction, ce même code garde ses noms pour lui, devient testable, et rattachable à une commande de terminal, ce qui rejoint le second sens du mot.


L'autre sens du mot : la commande installée

Le même terme désigne une seconde chose, souvent confondue avec la première. Un package publié peut déclarer des points d'entrée dans son fichier de configuration : chacun crée une commande de terminal qui appelle une fonction précise du projet. C'est ainsi que pip installe des commandes utilisables sans écrire python devant.

BASH
pip install ruff
ruff check .

Les deux notions se ressemblent sans se remplacer, d'où l'intérêt de savoir laquelle on cherche.

Point de comparaisonLa garde dans le fichierLa déclaration du projet
Où elle s'écritAu bas du script concernéDans le fichier de configuration du paquet
Ce qu'elle produitUn fichier qui se comporte autrement selon qu'il est lancé ou importéUne commande disponible dans le terminal après installation
Quand elle sertDès qu'un fichier est à la fois script et bibliothèqueQuand un projet doit s'utiliser comme un vrai outil


Quand la garde ne sert à rien

Elle n'est ni magique ni obligatoire. Un fichier de fonctions jamais lancé directement n'a rien à protéger. Un script jetable de dix lignes, écrit pour tourner une fois et jamais importé, n'en a pas besoin non plus.

L'erreur classique est de la recopier partout sans savoir pourquoi. L'erreur inverse est de l'oublier quand elle compte : un fichier qui grandit, qu'un collègue finit par importer, ou qu'une suite de tests charge pour vérifier une seule fonction. Le bon réflexe est de se demander, une fois par fichier, si quelqu'un pourrait l'importer.


Questions fréquentes

Question

Faut-il un fichier main.py comme dans d'autres langages ?

Non, le nom du fichier importe peu pour Python : c'est celui qu'on passe à la commande qui devient le point d'entrée, quel qu'il soit. Seule exception, le fichier __main__.py placé dans un dossier de paquet, qui rend ce dossier lançable avec python -m monpaquet et sert de porte officielle au projet.

Question

Pourquoi mon script semble-t-il s'exécuter deux fois ?

Parce que le même fichier est chargé sous deux identités : une fois comme fichier lancé, sous le nom __main__, et une fois comme module importé, sous son vrai nom. Python garde alors deux exemplaires distincts en mémoire, avec deux jeux de variables globales indépendants. La garde ne suffit pas toujours : il faut aussi éviter qu'un fichier lancé finisse par s'importer lui-même.

Question

Que se passe-t-il si les guillemets ou les tirets bas sont mal écrits ?

Rien de visible, ce qui rend la faute coûteuse. Écrire if __name__ == "main" produit une comparaison valide mais toujours fausse : le bloc ne s'exécute jamais, sans qu'aucune erreur ne s'affiche. Une faute sur la variable elle-même est plus bavarde, puisqu'un nom inconnu lève une NameError. Comptez donc deux tirets bas de chaque côté du mot, et vérifiez le mot exact entre les guillemets.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.