Accéder au contenu principal

Portée des variables Python et explication de la règle LEGB

Veuillez découvrir ce que sont les portées de variables et vous familiariser avec la règle « LEGB ». Vous serez également confronté à des scénarios où vous pourrez observer les mots-clés globaux et non locaux en action.
Actualisé 11 sept. 2025  · 8 min de lecture

Il est frustrant de voir apparaître les messages « nom non défini » ou « variable locale référencée avant attribution » immédiatement après avoir écrit quelques lignes. Le code semble correct, mais Python n'est pas d'accord. La cause principale est presque toujours la portée : où un nom est visible et à quel objet il fait référence à ce moment-là.

Une fois que vous comprenez le fonctionnement de la recherche de noms en Python, souvent résumé par la règle LEGB, ces erreurs deviennent prévisibles et faciles à corriger. Dans ce tutoriel, je vais vous présenter étape par étape les variables et les portées en Python.

Qu'est-ce qu'une variable ?

Une variable est un nom associé à un objet. En Python, vous créez une liaison avec l'opérateur d'affectation =. Les noms ne sont pas saisis ; ils peuvent faire référence à n'importe quel objet (chaîne, entier, liste, fonction, etc.).

customer_name = "Ava Torres"
order_count = 1
total_cents = 1 + 2 * 300  # evaluated first, then bound

Veuillez respecter ces règles et conventions lors de la dénomination des variables afin d'éviter les erreurs de syntaxe et les bugs subtils.

  • Veuillez utiliser uniquement des lettres, des chiffres et des traits de soulignement ; les noms ne peuvent pas commencer par un chiffre.
  • Veuillez éviter d'utiliser des mots-clés tels que True, for ou class comme noms.
  • Veuillez éviter de masquer les fonctions intégrées telles que list, dict, sum ou max.
  • Il est préférable d'utiliser « snake_case » pour une meilleure lisibilité (PEP 8).

Ces exemples illustrent ce qu'il convient d'éviter et les erreurs générées par Python :

first string value = "First string"  # spaces not allowed
# SyntaxError: invalid syntax

1st_value = 10  # cannot start with a digit
# SyntaxError: invalid decimal literal

True = "yes"  # cannot assign to a keyword
# SyntaxError: cannot assign to True

Fonctionnement de la portée en Python (LEGB)

La portée est la zone du code dans laquelle un nom est visible. Lorsque vous utilisez un nom, Python le recherche dans cet ordre (LEGB) :

  • Local: la portée de la fonction actuelle.
  • Enclosing: toutes les portées de fonction externes (pour les fonctions imbriquées).
  • Global: niveau supérieur du module (espace de noms du module).
  • Intégrés: noms définis par Python dans builtins (par exemple, len, print).

Les noms sont stockés dans des espaces de noms (considérez-les comme des dictionnaires associant des noms à des objets). La portée concerne les espaces de noms que Python consulte pour résoudre un nom à un moment donné dans le code.

Portée locale

Les noms attribués à l'intérieur d'une fonction sont locaux à cette fonction, sauf indication contraire. Ils ne sont pas accessibles en dehors de la fonction.

def show_order_id():
    order_id = 42
    print("inside function:", order_id)

show_order_id()
print("outside function:", order_id)  # NameError

Python détermine la portée lors de la compilation. Si une fonction assigne une valeur à un nom n'importe où dans son corps, toutes les utilisations de ce nom dans la fonction sont considérées comme locales, ce qui conduit à une erreur courante d'UnboundLocalError lorsque vous lisez avant d'assigner :

discount_rate = 0.10  # module-level (global)

def price_with_discount(amount_cents):
    print("configured discount:", discount_rate)  # looks local because of the assignment below
    discount_rate = 0.20  # assignment makes 'discount_rate' local in this function
    return int(amount_cents * (1 - discount_rate))

# UnboundLocalError: cannot access local variable 'discount_rate' where it is not associated with a value

Pour utiliser le nom au niveau du module dans la fonction, veuillez soit éviter de lui attribuer une valeur, soit le marquer comme « global » (voir ci-dessous).

Portée englobante (fermetures)

Les fonctions imbriquées peuvent accéder aux noms de la fonction qui les englobe immédiatement. Pour lier à nouveau un tel nom (et non simplement le lire), veuillez le déclarer comme suit : ` nonlocal`.

def make_step_counter():
    count = 0  # enclosing scope for 'increment'

    def increment():
        nonlocal count  # rebind the 'count' in the nearest enclosing function
        count += 1
        return count

    return increment

step = make_step_counter()
print(step())  # 1
print(step())  # 2

Sans l'instruction ` nonlocal`, l'affectation à ` count ` à l'intérieur de ` increment() ` créerait un nouveau nom local et laisserait le nom externe ` count ` inchangé.

Portée mondiale

Les noms attribués au niveau supérieur d'un module sont stockés dans l'espace de noms global du module. Toute fonction peut les lire. Pour attribuer un nom au niveau du module à partir d'une fonction, veuillez le déclarer à l'intér global.

greeting = "Hello"

def greet_city(city_name):
    print(greeting, city_name)  # reads global

def set_greeting(new_greeting):
    global greeting
    greeting = new_greeting     # rebinds global

greet_city("Nairobi")  # Hello Nairobi
set_greeting("Hi")
greet_city("Nairobi")  # Hi Nairobi

Veuillez utiliser l'global e avec modération. Il est préférable de transmettre des valeurs en tant que paramètres et de renvoyer des résultats afin de garantir la testabilité et la prévisibilité du code.

Portée intégrée (et remarque sur les mots-clés)

La portée intégrée contient des noms tels que len, print et Exception. Veuillez éviter de les masquer, sinon vous perdrez l'accès à la fonction intégrée pour cette portée.

list = [1, 2, 3]     # shadows the built-in 'list' constructor
list("abc")          # TypeError: 'list' object is not callable
del list             # fix by deleting the shadowing name

Les mots-clés (tels que if, for, def) font partie de la syntaxe Python, et non de l'espace de noms intégré, et ne peuvent jamais être utilisés comme identifiants.

Blocs, boucles et compréhensions

Les instructions de bloc et les compréhensions Python ont des comportements de portée spécifiques qui surprennent souvent les développeurs provenant d'autres langages.

Il n'existe pas de portée de bloc pour if/for/while/with

Les affectations à l'intérieur de ces blocs affectent la portée qui les contient (fonction ou module). Les variables de boucle restent également définies après la fin de la boucle.

if True:
    status = "ready"
print(status)  # "ready"

for i in range(3):
    pass
print(i)  # 2 (the last value from the loop)

Les compréhensions isolent leur variable d'itération.

Les compréhensions de listes, de dictionnaires et d'ensembles ont leur propre portée locale pour les variables de boucle. La variable d'itération ne fuit pas dans la portée environnante.

numbers = [1, 2, 3]
[x for x in numbers]
print("x" in globals() or "x" in locals())  # False

Python 3.12 (PEP 709) a intégré les compréhensions pour améliorer la vitesse tout en conservant cette isolation ; vous bénéficiez toujours de variables de boucle claires et sans fuite, avec une exécution plus rapide.

En utilisant le global Mot-clé

Déclarez un nom comme global à l'intérieur d'une fonction lorsque vous avez besoin de relier une variable au niveau du module. Veuillez placer la déclaration près du début de la fonction afin qu'il soit clair quelle variable vous modifiez.

tax_rate = 0.08

def configure_tax(rate):
    global tax_rate
    tax_rate = float(rate)

def total_with_tax(cents):
    return int(cents * (1 + tax_rate))

configure_tax(0.10)
print(total_with_tax(1000))  # 1100

En utilisant le nonlocal Mot-clé

Veuillez utiliser nonlocal pour redéfinir un nom à partir de la portée de fonction englobante la plus proche. Ceci est courant dans les fermetures qui conservent l'état.

def make_accumulator(start=0):
    total = start
    def add(amount):
        nonlocal total
        total += amount
        return total
    return add

acc = make_accumulator()
print(acc(5))   # 5
print(acc(10))  # 15

L'utilisation de l'instruction « nonlocal » pour un nom non défini dans une fonction englobante constitue une erreur de type « SyntaxError ». Si le nom est global, veuillez utiliser global à la place.

locals() et globals() en 2025

Ces fonctionssont utiles pour l'inspection et le débogage, mais ne doivent pas être utilisées pour mettre à jour des variables. À partir de Python 3.13 (PEP 667), chaque appel à locals() dans une fonction renvoie un instantané indépendant. La modification de cet instantané n'affecte pas les variables locales réelles. J'ai confirmé ce comportement en exécutant l'extrait de code suivant sur Python 3.13 :

def probe():
    project = "alpha"
    snap1 = locals()
    snap1["project"] = "beta"  # edits the snapshot only
    observed = project         # still "alpha"
    snap2 = locals()           # new snapshot
    return snap1["project"], observed, snap2["project"]

print(probe())  # ('beta', 'alpha', 'alpha')

Veuillez utiliser globals() de manière similaire pour l'espace de noms du module. Lors de la rédaction du code d'une application, privilégiez les paramètres explicites et les valeurs de retour plutôt que les recherches dynamiques.

Erreurs courantes et solutions pour les résoudre

Ces erreurs représentent la plupart des erreurs liées à la portée que j'observe dans la pratique.

  • UnboundLocalError à partir de l'affectation dans une fonction : Python considère un nom comme local s'il est attribué n'importe où dans la fonctionon. Veuillez déplacer la lecture après l'affectation, renommer ou ajouter global/nonlocal selon le cas.
  • Attente d'une portée de bloc : Les noms attribués dans les instructions if/for/while/with persistent dans la portée qui les contient. Utilisez des fonctions d'aide plus strictes pour restreindre la portée.
  • Ombres portées intégrées : Veuillez éviter les noms d'identifiants tels que « list », « dict », « sum », « id » ou « min ». Privilégiez des noms descriptifs tels que « customer_list » ou « min_allowed ».
  • Omission de l'nonlocal e dans les fermetures : Si vous avez l'intention de mettre à jour une variable de fonction externe, veuillez la déclarer comme non locale. Sinon, vous créez une nouvelle variable locale et la valeur externe ne change pas.
  • Confusion entre les mots-clés et les fonctions intégrées : Les mots-clés (syntaxe) ne peuvent en aucun cas être utilisés comme noms. Les éléments encastrés peuvent être masqués, mais cela n'est pas recommandé.

Meilleures pratiques pour simplifier la portée

Ces pratiques facilitent la lecture, le test et le débogage du code.

  • Privilégiez les fonctions restreintes et ciblées. Définissez les variables dans la portée la plus étroite possible.
  • Transmettre les données via des paramètres et des valeurs de retour. Réduisez au minimum l'état au niveau du module.
  • Veuillez utiliser les fermetures de manière intentionnelle. Veuillez documenter le nom externe qu', une fonction imbriquée, capture, et utilisez nonlocal lorsque vous avez réellement besoin de le relier.
  • Veuillez choisirdes noms descriptifset non conflictuels. Un trait de soulignement en début de nom (par exemple, _cache) indique une utilisation interne.
  • Considérezlocals()/globals() comme des diagnostics en lecture seule, et non comme un mécanisme de configuration.

Conclusion

Python résout les noms en recherchant dans les portées locales → englobantes → globales → intégrées. Comprendre cet ordre, et savoir quand utiliser global ou non local, permet d'éviter des erreurs courantes telles que NameError et UnboundLocalError. Limitez les variables au champ d'application le plus restreint possible, évitez de masquer les fonctions intégrées et utilisez les fermetures de manière réfléchie. Avec ce modèle mental, vos fonctions se comportent de manière prévisible et la portée cesse d'être une source de surprises.


Sejal Jaiswal's photo
Author
Sejal Jaiswal
LinkedIn

J'ai travaillé dans différents secteurs d'activité et j'ai porté plusieurs casquettes : développeur de logiciels, chercheur en apprentissage automatique, scientifique des données, chef de produit. Mais au fond, je suis un programmeur qui aime apprendre et partager ses connaissances !

Sujets

En savoir plus sur Python

Cours

Introduction à Python

4 h
6.5M
Apprenez les bases de l’analyse de données avec Python en quatre heures et explorez ses principaux packages.
Afficher les détailsRight Arrow
Commencer le cours
Voir plusRight Arrow
Apparenté

Didacticiel

Fonctions lambda Python : Guide pour débutants

Découvrez les fonctions lambda Python, leur utilité et quand les utiliser. Comprend des exemples pratiques et des bonnes pratiques pour une mise en œuvre efficace.
Mark Pedigo's photo

Mark Pedigo

Didacticiel

Tutoriel sur la fonction range() en Python

Découvrez la fonction range() de Python et ses capacités à l'aide d'exemples.
Aditya Sharma's photo

Aditya Sharma

Didacticiel

Tutoriel sur les boucles Python

Tutoriel complet d'introduction aux boucles Python. Apprenez et pratiquez les boucles while et for, les boucles imbriquées, les mots-clés break et continue, la fonction range et bien plus encore.
Satyabrata Pal's photo

Satyabrata Pal

Didacticiel

30 astuces Python pour améliorer votre code, accompagnées d'exemples

Nous avons sélectionné 30 astuces Python intéressantes que vous pouvez utiliser pour améliorer votre code et développer vos compétences en Python.
Kurtis Pykes 's photo

Kurtis Pykes

Didacticiel

Séquence de Fibonacci en Python : Apprenez et explorez les techniques de codage

Veuillez découvrir le fonctionnement de la suite de Fibonacci. Veuillez explorer ses propriétés mathématiques et ses applications concrètes.
Laiba Siddiqui's photo

Laiba Siddiqui

Didacticiel

Tutoriel et exemples sur les fonctions et méthodes des listes Python

Découvrez les fonctions et méthodes des listes Python. Veuillez suivre les exemples de code pour list() et d'autres fonctions et méthodes Python dès maintenant.
Abid Ali Awan's photo

Abid Ali Awan

Voir plusVoir plus