Le scope délimite l'environnement dans lequel une variable ou une fonction peut être utilisée. Le terme « scope » vient de l'anglais. En français, on parle de la portée d'une variable. Le terme "scope" est cependant généralement admis en français.
En Python, la gestion des scopes (local, global, non local) assure que chaque variable reste confinée à son contexte, améliorant ainsi la lisibilité et la robustesse de vos programmes.
Introduction
Une variable a une portée qui définit la zone du programme dans laquelle elle est accessible. De manière générale, on parlera de deux types de scope : global et local.
Scope local
Le scope local concerne les variables définies à l'intérieur d'une fonction.
Scope global
Le scope global englobe les variables déclarées en dehors des fonctions.
Exemples
Prenons un exemple où la variable x est déclarée dans le scope global, et accessible à l'intérieur d'une fonction :
def f1(): print(x) x = 5 f1() print(x)
La variable x est définie en dehors de la fonction, donc dans le scope global, ce qui permet à f1 d'y accéder.
Prenons un deuxième exemple, où l'on redéfinit la variable x dans le scope local. C'est la variable locale qui sera utilisée à l'intérieur de la fonction, même si une variable x existe dans le scope global.
def f1(): x = 2 print(x) x = 1 print(x) f1() print(x)
Modification d'une variable globale
Si l'on modifie une variable globale dans une fonction, cela provoque une UnboundLocalError. En réalité, Python détecte une assignation locale de x, de ce fait, il n'est pas possible d'utiliser la variable globale, ni la variable locale car elle est déclarée après le print.
def f1(): print(x) x = 5 x = 1 f1() # Provoque UnboundLocalError
Il faudrait assigner x avant le print :
def f1(): x = 5 print(x) x = 1 f1()
L'instruction global
Il est possible de modifier une variable globale depuis l'intérieur d'une fonction. Mais pour cela, il faut déclarer explicitement que l'on veut utiliser la variable du scope global avec le mot-clé global.
def f1(): global x print(x) x = 5 x = 1 f1() print(x)
Attention
Il est fortement déconseillé d'utiliser le mot-clé global, car cela peut rendre le code plus difficile à maintenir.
On en parlait plus en détail dans le glossaire sur les fonctions.
Les fonctions globals et locals
Il est possible d'utiliser les fonctions globals et locals pour visualiser le contenu des espaces sous forme de dictionnaires.
def f1(): x = 5 print(x) print(globals()) print(locals())
À noter
À noter que si vous utilisez locals dans l'espace global, vous récupérez le contenu de l'espace global.
Ces fonctions sont utiles pour le débogage, et il est même possible de modifier des variables globales via globals(), bien que cela doive être utilisé avec précaution.
def f1(): x = 5 print(x) globals()["x"] = 100 x = 1 print(x) f1() print(x)
Argument par Défaut sur un Objet Mutable
Quand une fonction est définie avec un argument par défaut mutable, ce dernier est créé une seule fois. De ce fait, il va garder sa valeur entre les appels.
def f1(liste=list()): print(liste) liste.append("Patrick") for _ in range(5): f1()
Mutable vs immuable
Les comportements vont être différents en fonction de si l'objet est mutable ou immuable. Lorsqu'on modifie un objet mutable sans le passer en argument, l'objet original est modifié :
def f1(): print(liste) liste.append("Patrick") liste = list() for _ in range(5): f1()
Avec un objet immuable, nous l'avons vu au début de l'article, toute modification crée une nouvelle variable locale.
non local
Le mot-clé non local est utilisé dans les fonctions imbriquées pour modifier une variable du scope englobant, sans qu'elle soit globale.
def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter c = make_counter() print(c()) # 1 print(c()) # 2 print(c()) # 3