La ligne la plus bizarre de Python — démystifiée
Ouvre presque n'importe quel fichier Python et tu finiras par voir ça en bas :
if __name__ == "__main__":
main()
Ça ressemble à un peu de boilerplate magique. C'est en fait une fonctionnalité très pratique une fois que tu sais ce qu'elle fait — et elle existe parce que Python ne trace pas de ligne entre « scripts » et « bibliothèques ».
Le contexte : deux façons d'utiliser un fichier
Chaque fichier .py en Python peut être utilisé de deux façons :
- Comme un script — tu le lances directement avec
python3 file.py. - Comme un module — un autre fichier l'importe avec
import file.
Le langage ne te fait pas déclarer lequel tu écris. Tout fichier peut finir par faire les deux.
Considère un fichier appelé math_helpers.py :
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
# Test rapide pendant le développement
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Si tu lances ce fichier directement, il affiche la sortie de test — parfait. Mais si un autre fichier fait import math_helpers, ces instructions print s'exécutent pendant l'import. Chaque utilisateur du module voit ta sortie de développement. Pas parfait.
Ce qu'est __name__
Chaque module Python a une variable intégrée appelée __name__. Python la définit automatiquement :
- Quand le fichier est importé,
__name__est défini au nom d'import du module —"math_helpers"dans l'exemple ci-dessus. - Quand le fichier est lancé directement, Python définit
__name__à la chaîne spéciale"__main__".
Ça te donne une façon de savoir dans quel mode tu es. Enveloppe le code « script uniquement » dans un test :
# math_helpers.py
def mean(values):
return sum(values) / len(values)
def median(values):
s = sorted(values)
mid = len(s) // 2
if len(s) % 2 == 0:
return (s[mid - 1] + s[mid]) / 2
return s[mid]
if __name__ == "__main__":
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
print("mean:", mean(numbers))
print("median:", median(numbers))
Maintenant python3 math_helpers.py affiche la sortie de test. Mais import math_helpers depuis un autre fichier saute le bloc entièrement — les fonctions sont disponibles, et rien d'indésirable ne s'exécute.
Le compagnon courant : une fonction main()
La plupart des vrais scripts grandissent une fonction main() dédiée et gardent le bloc de garde minuscule :
# process_orders.py
import sys
def load_orders(path):
with open(path) as f:
return [line.strip() for line in f if line.strip()]
def process(orders):
for order in orders:
print(f"Processing {order}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 process_orders.py <file>")
sys.exit(1)
orders = load_orders(sys.argv[1])
process(orders)
if __name__ == "__main__":
main()
Pourquoi se donner la peine d'une main() au lieu de mettre la logique directement sous la garde if ?
- Testabilité. Tu peux importer le module et appeler
main()(ou n'importe quel helper) depuis des tests. - Variables locales. Tout ce qui est défini dans
main()est une variable locale, pas un nom de niveau module. Ça évite les collisions de noms accidentelles et rend la surface publique du module plus propre. - Lisibilité. Le bloc de garde fait maintenant deux lignes — un « point d'entrée du script » clair plutôt qu'un tas de logique.
Une démonstration rapide
Tu peux voir le comportement directement :
Quand tu lances l'extrait ci-dessus avec Python, il affiche __name__ is: __main__ et « being run as a script ». Si un autre fichier l'avait importé, le même test afficherait l'autre branche.
Quand tu n'as pas besoin de la garde
Plein de fichiers Python n'en grandissent jamais. Les scripts courts que personne n'importerait jamais vont bien sans :
# one_off_rename.py
import os
for name in os.listdir("."):
if name.endswith(".txt"):
os.rename(name, name.lower())
C'est parfaitement bon. Tu ne construis pas de bibliothèque ; personne ne va importer ça. Au moment où il y a de la logique réutilisable dans un fichier, cependant — et que tu veux garder du code à effets de bord à côté — utilise la garde.
Points d'entrée pour les packages installés
Une fois que tu publies ton code comme un vrai package, il y a un mécanisme plus formel : les entry_points dans les métadonnées de ton package, qui mappent une commande à une fonction. Les utilisateurs qui installent ton package obtiennent une commande shell qui appelle directement la fonction. Mais pour les scripts lancés depuis un dossier sur ta propre machine, la garde __main__ est l'outil standard.
On conclut ce chapitre
Tu as maintenant :
- Des fonctions pour nommer ta logique.
*args/**kwargspour des appels flexibles.- Des lambdas pour des fonctions jetables.
- Des décorateurs et annotations de type pour envelopper et documenter ces fonctions.
- Des modules, pip et environnements virtuels pour découper le code à travers fichiers et projets.
- La garde
__main__pour laisser scripts et modules coexister.
Ensuite : les classes
Tu as surtout associé des fonctions à des données simples — dicts, listes, tuples. Le chapitre suivant introduit les classes, la façon de Python de lier données et comportement, et l'endroit où vivent les concepts comme self, __init__, l'héritage et les dataclasses.
Questions fréquentes
Que fait if __name__ == '__main__' ?
if __name__ == '__main__' ?Il n'exécute le bloc en dessous que quand le fichier est lancé directement (pas quand le fichier est importé comme module). Ça te permet d'écrire un fichier .py qui peut être à la fois lancé comme script ou importé pour ses fonctions et classes — sans que les actions du script arrivent pendant l'import.
Python a-t-il besoin d'une fonction main ?
Non. Les fichiers Python s'exécutent automatiquement de haut en bas. Mais dès qu'un fichier a de la logique que tu veux aussi pouvoir importer, la garde if __name__ == '__main__' devient importante — et mettre le travail de niveau racine du script dans une fonction main() est une habitude compagnon courante.
Quelle est la différence entre __name__ et __main__ ?
__name__ et __main__ ?__name__ est une variable spéciale que Python définit dans chaque module. Si le fichier est importé, __name__ est le nom du module (comme 'util'). Si le fichier est lancé directement, Python définit __name__ à la chaîne '__main__'. Le test if compare les deux.