Portée en Python
Apprenez la portée en Python et la règle LEGB : portées locale, englobante, globale et intégrée avec des exemples clairs, pièges et mots-clés global/nonlocal.
Comprendre la portée en Python
La portée détermine où un nom de variable est visible et combien de temps il existe. Chaque nom que vous créez — une variable, une fonction, une classe — appartient à exactement une portée. Lorsque Python rencontre un nom, il parcourt les portées dans un ordre strict jusqu'à trouver ce nom ou lever une NameError.
Cette page couvre :
- Les quatre niveaux de portée et la règle de recherche LEGB
- Les mots-clés
globaletnonlocal - Les pièges courants : masquage,
UnboundLocalErroret fuite de noms - Comment inspecter les portées à l'exécution
La règle LEGB
Python résout les noms en quatre couches, recherchées de la plus intérieure à la plus extérieure :
| Niveau | Signifie | Ce qu'elle contient |
|---|---|---|
| L | Local | Noms définis à l'intérieur de la fonction courante |
| E | Enclosing (englobant) | Noms dans toute fonction englobante (externe), pour les fonctions imbriquées |
| G | Global | Noms définis au niveau supérieur du module courant |
| B | Built-in (intégré) | Noms préchargés par Python — print, len, range, type, etc. |
Python s'arrête à la première correspondance. Si aucune correspondance n'est trouvée dans aucune couche, une NameError est levée.
Portée locale
Un nom est local lorsqu'il est assigné à l'intérieur d'une fonction. Il est créé quand la fonction est appelée et détruit quand la fonction retourne. Les noms locaux sont invisibles en dehors de la fonction.
def greet():
message = "Hello, World!" # local variable
print(message) # accessible here
greet()
# Output: Hello, World!
print(message) # NameError: name 'message' is not definedPourquoi la portée locale est importante
La portée locale vous permet d'utiliser des noms simples et descriptifs comme total, result ou i à l'intérieur de chaque fonction, sans qu'aucun d'eux entre en conflit avec les autres ou avec le code au niveau du module.
def calculate_area(radius):
pi = 3.14159 # local to this function
area = pi * radius ** 2
return area
def calculate_volume(radius, height):
pi = 3.14159 # completely separate local 'pi'
volume = pi * radius ** 2 * height
return volume
print(calculate_area(5)) # 78.53975
print(calculate_volume(5, 10)) # 785.3975Les deux fonctions utilisent pi indépendamment. Il n'y a aucun conflit.
Portée englobante
Quand une fonction est définie à l'intérieur d'une autre fonction, la fonction interne peut lire les noms de la fonction externe (englobante). C'est le E dans LEGB.
def outer():
color = "blue" # enclosing variable
def inner():
print(color) # reads from enclosing scope
inner()
outer()
# Output: blueLa fonction interne peut lire color sans aucun mot-clé particulier, car Python remonte automatiquement jusqu'à la portée englobante.
Modifier une variable englobante avec nonlocal
Lire une variable englobante est automatique, mais l'assigner nécessite le mot-clé nonlocal. Sans lui, Python traite l'assignation comme la création d'une nouvelle variable locale, et non comme la modification de la variable englobante.
def make_counter():
count = 0 # enclosing variable
def increment():
nonlocal count # declare intent to modify the enclosing 'count'
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3Chaque appel à counter() modifie la même variable count. Ce schéma est à la base des closures — voir Python Closures pour une analyse approfondie.
Portée globale
Les noms définis au niveau supérieur d'un module (en dehors de toute fonction) sont globaux. Ils sont accessibles depuis n'importe où dans le même module, y compris à l'intérieur des fonctions.
language = "Python" # global variable
def display_language():
print(language) # reads global without any keyword
display_language()
# Output: PythonModifier une variable globale avec global
Vous pouvez lire une variable globale depuis l'intérieur d'une fonction sans aucun mot-clé. Mais si vous souhaitez lui assigner une valeur, vous devez d'abord la déclarer avec global :
total = 0 # global variable
def add_to_total(n):
global total # declare intent to modify the global
total += n
add_to_total(5)
add_to_total(3)
print(total) # 8Sans global total, la ligne total += n lèverait une UnboundLocalError car Python traiterait total comme une variable locale qui n'a pas encore été assignée.
Pour plus d'informations sur les variables globales, voir Python Global Variables.
Quand éviter global
L'utilisation intensive de global rend le code plus difficile à tester et à raisonner. Préférez retourner des valeurs depuis les fonctions et passer les données en arguments. Réservez global pour un véritable état au niveau du module — indicateurs de configuration, compteurs ou caches — et utilisez-le avec parcimonie.
Portée intégrée
La portée intégrée contient des noms que Python fournit automatiquement. Ils sont disponibles dans chaque module sans aucun import.
Les noms intégrés courants incluent print, len, range, type, int, str, list, dict, set, tuple, open, input, max, min, sum, sorted, enumerate, zip et map.
Ne masquez pas les noms intégrés
Comme la portée intégrée est recherchée en dernier, tout nom local ou global avec la même orthographe la masquera. C'est une erreur courante :
# Bad: shadows the built-in 'list'
list = [1, 2, 3]
print(type(list)) # <class 'list'> — still works here
new = list([4, 5]) # TypeError: 'list' object is not callableSupprimez le nom masquant pour restaurer l'intégré :
del list # remove the local/global shadowing name
new = list([4, 5]) # works again: [4, 5]Le module intégré est disponible sous le nom builtins si vous avez jamais besoin d'y accéder explicitement :
import builtins
print(builtins.len([1, 2, 3])) # 3Pièges courants
UnboundLocalError
L'erreur de portée la plus fréquente en Python consiste à lire un nom avant de lui assigner une valeur à l'intérieur d'une fonction, lorsqu'il existe également une assignation à ce nom quelque part dans la même fonction :
x = 10
def bad_func():
print(x) # UnboundLocalError! Python sees x = 20 below
x = 20 # this makes 'x' local for the whole function
bad_func()Python décide à la compilation que x est local (parce qu'il est assigné dans la fonction). La tentative de le lire avant l'assignation lève UnboundLocalError: local variable 'x' referenced before assignment.
Corrigez cela en déclarant global x ou en n'assignant pas x à l'intérieur de la fonction.
Masquage de variable
Une variable locale qui partage un nom avec une variable globale masque silencieusement la globale. C'est généralement intentionnel, mais cela peut provoquer des bogues subtils lorsque vous pensez lire la globale :
x = 10 # global
def my_func():
x = 20 # local — shadows the global
print(x) # 20, not 10
my_func()
print(x) # 10 — global unchangedInspecter la portée à l'exécution
Python expose le contenu de la portée courante via deux fonctions intégrées.
locals() retourne un dictionnaire de la portée locale courante (ou l'espace de noms au niveau du module si appelée au niveau supérieur) :
def show_locals():
a = 1
b = "hello"
print(locals()) # {'a': 1, 'b': 'hello'}
show_locals()globals() retourne le dictionnaire de l'espace de noms global (au niveau du module) :
language = "Python"
print("language" in globals()) # TrueCes fonctions sont utiles pour le débogage et l'introspection, mais ne doivent pas être utilisées pour manipuler des variables dynamiquement dans le code de production.
Portée et fonctions
Les fonctions en Python sont des objets et sont elles-mêmes des noms qui vivent dans une certaine portée. Une fonction définie au niveau supérieur d'un module est globale ; une fonction définie à l'intérieur d'une autre fonction est locale à la fonction englobante.
def outer():
def helper(): # helper is local to outer
return 42
return helper()
print(outer()) # 42
# helper() # NameError: helper is not defined hereVoir Python Functions pour la définition des fonctions, et Python Lambda pour les fonctions anonymes qui obéissent également à la règle LEGB.
Référence rapide
| Mot-clé | Effet |
|---|---|
| (aucun) | Lecture depuis la portée englobante la plus proche selon la recherche LEGB |
global x | Indique à la fonction courante que x fait référence au nom au niveau du module |
nonlocal x | Indique à la fonction courante que x fait référence au nom dans la fonction englobante la plus proche |