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.
def additionner(a, b):
return a + b
if __name__ == "__main__":
print(additionner(2, 3)) # ne s'exécute qu'au lancement directLancé 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é.
| Situation | Contenu 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.
# 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.
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.
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.
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 comparaison | La garde dans le fichier | La déclaration du projet |
|---|---|---|
| Où elle s'écrit | Au bas du script concerné | Dans le fichier de configuration du paquet |
| Ce qu'elle produit | Un fichier qui se comporte autrement selon qu'il est lancé ou importé | Une commande disponible dans le terminal après installation |
| Quand elle sert | Dès qu'un fichier est à la fois script et bibliothèque | Quand 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
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.
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.
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.