Python global - Éviter les pièges des variables globales

Denis Ribeiro .

25 février 2026

Exemple Python : sans mot-clé `global`, la fonction crée une variable locale. Avec `global`, elle modifie la variable globale.

Quand une fonction doit partager un état avec le reste du module, le vrai sujet n’est pas une « fonction globale », mais la portée des noms et la façon dont Python traite l’affectation. Je vais montrer ce que fait réellement global, dans quels cas il est utile, pourquoi il déclenche souvent des erreurs, et quelles alternatives je privilégie pour garder un code plus lisible. Vous repartirez avec des exemples simples, un tableau de comparaison et une règle pratique pour savoir quand l’utiliser, ou l’éviter.

Les points à retenir avant d’utiliser un état global en Python

  • global ne crée pas une fonction : c’est une instruction qui dit à Python d’utiliser un nom défini au niveau du module.
  • Si une fonction ne fait que lire une variable globale, elle n’a généralement pas besoin de global.
  • Le piège classique vient d’une affectation dans la fonction : Python considère alors le nom comme local par défaut.
  • nonlocal sert pour une variable d’une fonction englobante, pas pour une variable du module.
  • Pour un code maintenable, les paramètres, les valeurs de retour et les objets sont souvent meilleurs que l’état partagé.

Exemple de fonction global Python montrant les portées globale, englobante et locale avec les mots-clés `global` et `nonlocal`.

Ce que fait vraiment l’instruction global

En Python, global est une directive de portée, pas un mécanisme magique. La documentation officielle rappelle qu’elle s’applique au bloc courant et qu’elle indique à l’interpréteur qu’un nom doit être résolu au niveau du module. Autrement dit, elle ne « rend » pas une fonction globale et ne modifie pas le comportement de Python partout dans le programme.

Le point le plus important est simple : si vous assignez à un nom dans une fonction, Python le traite comme local, sauf si vous le déclarez explicitement avec global. C’est pour cela que lire une variable globale est souvent possible sans rien écrire de spécial, alors que la réaffecter provoque vite une erreur ou un comportement inattendu.

Je résume la règle pratique ainsi : lecture seule, pas besoin de global ; réaffectation, déclaration obligatoire. La nuance paraît petite, mais elle explique à elle seule la majorité des bugs liés à la portée des variables. Et c’est justement là qu’il faut regarder les cas concrets pour comprendre ce qui se passe vraiment.

Lire, modifier ou réaffecter une variable globale

Le comportement change selon la nature de l’opération. Lire une valeur, modifier un objet mutable et réaffecter un nom ne sont pas la même chose pour Python, même si, à première vue, tout ressemble à une simple « mise à jour ».

compteur = 0

def afficher_compteur():
    print(compteur)  # lecture simple, pas besoin de global

def incrementer():
    global compteur
    compteur += 1
    return compteur

Dans le premier cas, la fonction lit la variable du module. Dans le second, elle réaffecte le nom compteur, donc elle doit signaler explicitement que ce nom appartient à l’espace global du module. Sans global, Python comprendrait que compteur est local à la fonction, ce qui crée un conflit au moment où il faut lire sa valeur avant de l’incrémenter.

total = 10

def ajouter():
    total += 1  # UnboundLocalError
    return total

Ici, l’erreur est classique : Python voit une affectation sur total, le considère comme local, puis se retrouve à devoir le lire avant qu’il ait reçu une valeur. C’est le fameux UnboundLocalError. La correction peut être global, mais ce n’est pas forcément la meilleure solution si la logique métier commence à grossir.

Il existe aussi un cas qui piège souvent les débutants : modifier un objet mutable n’est pas la même chose que réaffecter son nom.

journal = []

def ajouter_evenement():
    journal.append("connexion réussie")  # mutation, pas de global nécessaire

Le nom journal n’est pas réassigné, seul l’objet liste est modifié. En revanche, si vous écrivez journal = journal + ["connexion réussie"], vous faites une réaffectation et la logique change complètement. Cette distinction vaut de l’or quand on relit un script plusieurs semaines plus tard, parce qu’elle évite de confondre mutation d’objet et rebinding du nom. Et c’est précisément ce qui amène à comparer global à nonlocal et aux paramètres classiques.

Comparer global, nonlocal et les paramètres

Quand je vois du code avec des variables partagées, je commence presque toujours par me demander si le bon outil n’est pas simplement une valeur de retour, un paramètre explicite ou une fermeture avec nonlocal. Le choix dépend surtout de l’endroit où vit l’état et de la durée pendant laquelle il doit exister.

Outil Portée visée Usage typique Limite principale
global Variable du module Compteur simple, état partagé très ponctuel, script court Rend les dépendances implicites et complique les tests
nonlocal Variable d’une fonction englobante Fermeture qui doit conserver un état interne Ne fonctionne pas au niveau du module
Paramètres + retour Flux explicite entre fonctions Logique métier, traitement de données, code réutilisable Demande un peu plus de discipline à l’appelant
Objet ou dataclass État regroupé dans une structure Configuration, session, compteur, cache métier Nécessite une petite architecture supplémentaire

nonlocal est souvent la meilleure réponse quand une fonction interne doit ajuster un état défini dans la fonction parente. Exemple typique : un compteur encapsulé dans une fermeture. À l’inverse, si plusieurs fonctions du module manipulent la même donnée, je préfère presque toujours un objet dédié ou un conteneur explicite plutôt qu’un flot de variables globales. Le code devient plus lisible, et les effets de bord sont plus faciles à tracer.

Ce tableau aide à voir une chose essentielle : global agit au niveau du module, pas au niveau de la logique métier. Quand on confond les deux, on obtient du code qui fonctionne « par chance » jusqu’au moment où la base grossit, où les tests arrivent, ou où un second développeur modifie le même fichier. C’est là que les pièges deviennent visibles.

Les pièges qui cassent le plus souvent les scripts

Le premier piège est syntaxique : si vous utilisez un nom avant sa déclaration global dans le même bloc, Python peut lever une erreur de syntaxe ou refuser la logique. Le second est conceptuel : une affectation dans une fonction transforme un nom en variable locale, même si le même nom existe déjà au niveau du module.

Le troisième piège, que je vois souvent dans les scripts un peu pressés, consiste à confondre lecture, mutation et réaffectation. Une liste globale que l’on modifie avec append() n’a pas le même comportement qu’une variable qu’on réassigne à une nouvelle valeur. Cette différence semble technique, mais elle change directement la maintenabilité du programme.

  • Évitez de faire dépendre deux fonctions d’un même état caché si une valeur de retour suffit.
  • Ne surchargez pas des noms usuels comme list, open ou globals.
  • Gardez à l’esprit que globals() sert à inspecter le dictionnaire du module, pas à contourner proprement la portée.
  • Avec du code multithread ou asynchrone, l’état partagé devient plus fragile, surtout si plusieurs tâches peuvent l’écrire en même temps.
  • Les blocs exécutés via exec() ou du code généré dynamiquement ne partagent pas magiquement les mêmes règles de portée que le reste du fichier.

Je considère aussi que les variables globales rendent les tests plus difficiles à isoler. Un test qui modifie un état de module peut influencer le test suivant si la réinitialisation n’est pas impeccable. À partir de là, la vraie question n’est plus « puis-je utiliser global ? », mais plutôt « est-ce la bonne abstraction pour ce que je veux faire ? ». Et, très souvent, la réponse est non.

Quand éviter l’état global et quoi utiliser à la place

Dans les petits scripts, global peut dépanner. Dans une application, un service ou un projet amené à évoluer, je le réserve à des cas très limités. Dès qu’un état commence à porter de la logique, je préfère le faire passer par une structure plus explicite.

  • Utilisez des paramètres et des valeurs de retour quand la fonction transforme une donnée.
  • Utilisez une classe ou une dataclass quand plusieurs fonctions partagent le même état métier.
  • Utilisez nonlocal quand une fermeture doit conserver un état interne local au composant.
  • Utilisez une constante de module pour une valeur vraiment stable, pas pour un état qui change.
  • Utilisez un cache dédié ou functools.lru_cache plutôt qu’un bricolage global pour mémoriser des résultats.
from dataclasses import dataclass

@dataclass
class Compteur:
    valeur: int = 0

    def incrementer(self):
        self.valeur += 1
        return self.valeur

Ce type de structure est souvent plus facile à relire qu’une variable globale disséminée dans plusieurs fonctions. On sait où l’état vit, qui le modifie et à quel moment. En pratique, c’est ce qui réduit le plus les bugs de maintenance, bien plus qu’un simple « ça marche » en phase de prototype. C’est aussi la solution que je recommande quand un script commence à ressembler à une petite application.

La règle simple que j’applique avant d’écrire global

Avant d’écrire global, je me pose trois questions très concrètes : est-ce que je peux transmettre la valeur en paramètre, est-ce que je peux renvoyer un résultat proprement, et est-ce que cet état mérite d’être encapsulé dans un objet ? Si l’une de ces réponses est oui, je m’éloigne du global.

Je garde global pour des cas étroits, lisibles et contrôlés, comme un petit compteur de script ou un état de module vraiment simple. Dès qu’il faut coordonner plusieurs fonctions, gérer des tests fiables ou préparer une évolution future, je préfère un design explicite. En Python, ce choix n’est pas seulement une question de style : c’est souvent ce qui fait la différence entre un code qui tient dans le temps et un script qui devient pénible à faire évoluer.

Questions fréquentes

L'instruction `global` est une directive qui indique à l'interpréteur Python qu'un nom de variable doit être résolu au niveau du module (global) et non comme une variable locale à la fonction. Elle est nécessaire pour réaffecter une variable globale depuis l'intérieur d'une fonction.
Utilisez `global` lorsque vous devez modifier (réaffecter) une variable définie au niveau du module depuis l'intérieur d'une fonction. Pour une simple lecture d'une variable globale, `global` n'est pas nécessaire. C'est souvent utile pour de petits scripts ou des compteurs simples.
`global` s'applique aux variables définies au niveau du module (portée globale). `nonlocal` s'applique aux variables d'une fonction englobante, mais qui ne sont pas globales. Il est utilisé pour modifier une variable dans une portée extérieure, mais pas la portée du module lui-même.
L'utilisation excessive de `global` peut rendre le code difficile à lire, à tester et à maintenir. Les dépendances implicites entre les fonctions et l'état global augmentent les risques d'effets de bord inattendus, compliquant le débogage et l'évolution du programme.
Les alternatives incluent le passage de variables comme paramètres et le retour de valeurs, l'utilisation de classes ou de dataclasses pour encapsuler l'état, ou l'emploi de `nonlocal` pour les fermetures. Ces méthodes rendent le flux de données plus explicite et le code plus robuste.

Évaluer l'article

Moyenne: 0.0 / 5 · 0 évaluations

Tags

fonction global python python global variable python global dans fonction quand utiliser global python gérer état global python alternative global python
Autor Denis Ribeiro
Denis Ribeiro
Je m'appelle Denis Ribeiro et je suis passionné par les technologies, en particulier dans les domaines du web, de l'intelligence artificielle, des réseaux et de la sécurité. Fort de plusieurs années d'expérience en tant qu'analyste de l'industrie, j'ai eu l'occasion d'explorer en profondeur ces sujets, en me concentrant sur les évolutions et les tendances qui façonnent notre monde numérique. Mon expertise me permet d'analyser des données complexes et de les présenter de manière accessible, afin que chacun puisse comprendre les enjeux technologiques actuels. Je m'efforce d'apporter une perspective objective et factuelle à mes écrits, en vérifiant rigoureusement les informations pour garantir leur fiabilité. Je suis engagé à fournir à mes lecteurs des contenus précis, à jour et impartiaux, car je crois fermement que l'accès à une information de qualité est essentiel pour naviguer dans l'univers technologique en constante évolution. Mon objectif est de contribuer à une meilleure compréhension des défis et des opportunités que présente le monde numérique.

Commentaires (0)

Ajouter un commentaire