Le Concept de Portée (Scope) en Python

Le concept de portée (scope) définit la manière dont les variables et les noms sont recherchés dans votre code.
Elle détermine la visibilité d'une variable dans le programme.
La portée d’un nom ou d’une variable dépend de l’endroit où cette variable est créée dans le code.
En Python, la gestion de la portée repose sur une règle appelée LEGB.

La Règle LEGB

L'acronyme LEGB signifie :

  • Local : La portée locale d’une fonction ou d’une expression lambda.
    Elle contient les noms définis à l’intérieur de la fonction et n'est accessible que dans cette fonction.
  • Enclosing : La portée d’une fonction englobante dans le cas de fonctions imbriquées.
    Cette portée permet aux fonctions imbriquées d’accéder aux variables définies dans leur fonction parente.
  • Global : La portée au niveau du module. Les noms définis dans un module sont accessibles partout dans le code du module.
  • Built-in : La portée des noms intégrés de Python, contenant les mots-clés, fonctions et exceptions prédéfinis du langage.

Lorsqu’un nom est référencé dans un programme, Python suit l'ordre LEGB signifie :pour le rechercher et le résoudre.

Comprendre la Portée en Python

En programmation, la portée d’un nom définit la zone d’un programme où ce nom peut être utilisé sans ambiguïté.
On distingue généralement deux grandes portées:

  • Portée globale : Les noms définis ici sont accessibles dans tout le programme.
  • Portée locale : Les noms définis ici sont accessibles uniquement dans un bloc de code spécifique, comme à l'intérieur d'une fonction.

Pourquoi la notion de portée est-elle apparue ?

Dans les premiers langages de programmation (comme BASIC ) , toutes les variables étaient globales, ce qui posait de nombreux problèmes de maintenance et de débogage.
Toute partie du programme pouvait modifier n'importe quelle variable à tout moment, ce qui rendait le suivi des valeurs très difficile.

Python, comme d’autres langages modernes, utilise la notion de LEGB pour éviter ces problèmes en limitant la visibilité des variables .

La Différence Entre Portée et Espace de Noms

En Python, la notion de portée est liée à celle d’espace de noms (namespace).
Un espace de noms est un dictionnaire qui associe des noms à des objets

Par exemple, l’espace de noms d’un module est stocké dans module.__dict__ . Vous pouvez explorer les noms définis dans un module avec :

			python
			import sys
			print(sys.__dict__.keys())  # Affiche tous les noms du module sys
		

Utilisation de la Règle LEGB en Python

Lorsqu’un nom est utilisé, Python suit l’ordre LEGB pour rechercher ce nom :

  • Portée locale (L) : Python vérifie d’abord si le nom est défini dans la fonction ou la structure actuelle.
  • Portée englobante (E) : Si le nom n'est pas trouvé, Python cherche dans la fonction englobante (si applicable).
  • Portée globale (G) : Ensuite, Python cherche dans le module global.
  • Portée intégrée (B) : Enfin, Python recherche dans la portée des fonctions et mots-clés intégrés (builtins).

Si le nom n'existe pas dans ces portées, une erreur est levée (NameError).

Exemple d’application de LEGB

x = 10  # Portée globale

def outer():
    x = 20  # Portée englobante

    def inner():
        x = 30  # Portée locale
        print(x)  # Résout à 30

    inner()
    print(x)  # Résout à 20

outer()
print(x)  # Résout à 10
        

Modifier la Portée en Python

Python fournit deux mots-clés pour modifier le comportement standard de la portée :

1. Le mot-clé global

- Permet de modifier une variable globale à l’intérieur d’une fonction.

counter = 0  # Variable globale

def increment():
    global counter  # Déclare counter comme globale
    counter += 1

increment()
print(counter)  # Affiche 1
        

2. Le mot-clé nonlocal

- Permet de modifier une variable définie dans une portée englobante (non locale).

def outer():
    x = 10  # Variable englobante

    def inner():
        nonlocal x  # Modifie x de la fonction outer
        x += 5

    inner()
    print(x)  # Affiche 15

outer()
        

Autres Concepts Liés à la Portée

1. La Portée dans les Fonctions Imbriquées

Les fonctions imbriquées peuvent accéder aux variables de leur fonction englobante, mais elles ne peuvent pas les modifier sans nonlocal.

def outer():
	message = "Hello"

	def inner():
		print(message)  # Fonctionne (lecture)

	inner()
	

2. Portée Globale dans les Modules

Chaque module Python a sa propre portée globale , ce qui signifie que les variables globales définies dans un module ne sont pas visibles dans d'autres modules, sauf si elles sont importées .

# module1.py
x = 42

# module2.py
import module1
print(module1.x)  # Accès à x défini dans module1
	

3. Portée dans les Classes

Les classes ont une portée locale, mais leurs attributs sont accessibles via l’instance ou la classe elle-même.

class MyClass:
    attr = 100  # Portée de la classe

    def __init__(self):
        self.instance_attr = 200  # Portée de l'instance

print(MyClass.attr)  # 100
obj = MyClass()
print(obj.instance_attr)  # 200
	

4. Portée des Variables de Boucle

En Python, les variables définies dans une compréhension de liste sont locales à cette compréhension :

[item for item in range(5)]
print(item)  # Erreur : item n'existe pas hors de la compréhension
	

Fonctions Utiles pour Travailler avec les Portées

Python fournit des fonctions intégrées pour manipuler et explorer les portées :

  • globals() : Renvoie le dictionnaire des variables globales .
  • locals() : Renvoie le dictionnaire des variables locales .
  • dir(obj) : Liste les attributs et méthodes d’un objet.
  • vars(obj) : Renvoie obj.__dict__(utile pour les classes et modules).
print(globals())  # Affiche les variables globales
print(locals())  # Affiche les variables locales
		

Exemple LEGB avec une fonction Built-in

# Portée globale (G)
sum = "Je suis une chaîne de caractères"

def fonction_externe():
    # Portée englobante (E)
    sum = [10, 20, 30]

    def fonction_interne():
        # Portée locale (L)
        sum = 100
        print("Portée locale :", sum)

    fonction_interne()
    print("Portée englobante :", sum)

fonction_externe()
print("Portée globale :", sum)

# Récupérer la fonction sum() originale
import builtins
print("Somme correcte :", builtins.sum([1, 2, 3]))
        

Explication

  • Portée locale (L): La variable sum dans fonction_interne() masque les autres sum .
  • Portée englobante (E): sum dans fonction_externe() est utilisée si elle n’est pas redéfinie localement.
  • Portée globale (G): sum est une chaîne de caractères au niveau global.
  • Portée intégrée (B):: La fonction sum() intégrée ne fonctionne plus car sum a été redéfini. On la récupère avec builtins.sum() .

Conclusion

La portée des variables en Python est essentielle pour éviter les erreurs, réduire les bugs et mieux structurer son code.
La règle LEGB vous permet de comprendre comment Python recherche et résout les noms.

  • Éviter les conflits de noms
  • Améliorer la maintenabilité du code
  • Utiliser correctement les variables locales et globales

🔥 Bonne pratique : Évitez les variables globales autant que possible et préférez les variables locales.