W3docs

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 global et nonlocal
  • Les pièges courants : masquage, UnboundLocalError et 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 :

NiveauSignifieCe qu'elle contient
LLocalNoms définis à l'intérieur de la fonction courante
EEnclosing (englobant)Noms dans toute fonction englobante (externe), pour les fonctions imbriquées
GGlobalNoms définis au niveau supérieur du module courant
BBuilt-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 defined

Pourquoi 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.3975

Les 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: blue

La 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())  # 3

Chaque 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: Python

Modifier 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)            # 8

Sans 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.

python— editable, runs on the server

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 callable

Supprimez 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]))  # 3

Piè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 unchanged

Inspecter 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())  # True

Ces 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 here

Voir 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 xIndique à la fonction courante que x fait référence au nom au niveau du module
nonlocal xIndique à la fonction courante que x fait référence au nom dans la fonction englobante la plus proche

Entraînement

Pratique
En Python, quels sont les quatre types de portées dans l'ordre où elles sont vérifiées ?
En Python, quels sont les quatre types de portées dans l'ordre où elles sont vérifiées ?
Was this page helpful?