Python3 Espaces de noms et portée
Espace de noms
Tout d'abord, examinons un passage de la documentation officielle :
Un espace de noms est une correspondance entre des noms et des objets.La plupart des espaces de noms sont actuellement implémentés sous forme de dictionnaires Python.
Un espace de noms est une correspondance entre des noms et des objets. La plupart des espaces de noms sont actuellement implémentés sous forme de dictionnaires Python.
Les espaces de noms permettent d'éviter les conflits de noms dans les projets. Chaque espace de noms est indépendant et n'a aucune relation avec les autres, donc un seul espace de noms ne peut pas contenir de noms en double, mais des espaces de noms différents peuvent avoir le même nom sans aucun effet.
Prenons un exemple tiré d'un système informatique : un dossier (répertoire) peut contenir plusieurs dossiers, et chaque dossier ne peut pas contenir de fichiers portant le même nom, mais des fichiers dans des dossiers différents peuvent avoir le même nom.

Il existe généralement trois types d'espaces de noms :
- Noms intégrés (noms intégrés), noms intégrés au langage Python, tels que les noms de fonctions abs, char, et les noms d'exceptions BaseException, Exception, etc.
- Noms globaux (noms globaux), noms définis dans un module, enregistrant les variables du module, y compris les fonctions, les classes, les autres modules importés, ainsi que les variables et constantes au niveau du module.
- Noms locaux (noms locaux), noms définis dans une fonction, enregistrant les variables de la fonction, y compris les paramètres de fonction et les variables définies localement. (Ceux définis dans une classe sont également inclus.)

Ordre de recherche des espaces de noms :
Supposons que nous voulions utiliser la variable example, alors l'ordre de recherche de Python est :Espace de noms local -> Espace de noms global -> Espace de noms intégré。
Si la variable example n'est pas trouvée, il abandonnera la recherche et lèvera une exception NameError :
NameError: name 'example' is not defined.
Le cycle de vie d'un espace de noms :
Le cycle de vie d'un espace de noms dépend de la portée de l'objet. Si l'objet a terminé son exécution, le cycle de vie de cet espace de noms se termine.
Par conséquent, nous ne pouvons pas accéder aux objets d'un espace de noms intérieur depuis un espace de noms extérieur.
Exemple
var1 = 5
def some_func():
# var2 est un nom local
var2 = 6
def some_inner_func():
# var3 est un nom local imbriqué
var3 = 7
Comme le montre la figure ci-dessous, le même nom d’objet peut exister dans plusieurs espaces de noms.

Portée
Une portée est une région textuelle d’un programme Python où un espace de noms est directement accessible. « Directement accessible » signifie ici qu’une référence non qualifiée à un nom tente de trouver le nom dans l’espace de noms.
Une portée est la région textuelle d’un programme Python où un espace de noms est directement accessible.
Dans un programme Python, accéder directement à une variable parcourt toutes les portées, de l’intérieure à l’extérieure, jusqu’à ce qu’elle soit trouvée ; sinon, une erreur de variable non définie sera signalée.
En Python, les variables d’un programme ne sont pas accessibles depuis n’importe quel endroit ; les droits d’accès dépendent de l’endroit où la variable est assignée.
La portée d’une variable détermine quelle partie du programme peut accéder à un nom de variable donné.
Python possède au total 4 portées, qui sont :
Il existe quatre portées :
- L (Local): la couche la plus interne, contenant les variables locales, comme à l'intérieur d'une fonction/méthode.
- E (Enclosing): contient les variables non locales (non-local) et aussi non globales (non-global). Par exemple, avec deux fonctions imbriquées, si une fonction (ou classe) A contient une autre fonction B, alors pour les noms dans B, la portée dans A est non locale.
- G (Global): la couche la plus externe du script courant, comme les variables globales du module courant.
- B (Built-in): contient les variables/mots-clés intégrés, etc., recherchés en dernier.
Règle LEGB (Local, Enclosing, Global, Built-in) : l'ordre dans lequel Python recherche les variables est :L –> E –> G –> B。
- Local: la portée locale de la fonction courante.
- Enclosing: la portée de la fonction externe qui contient la fonction courante (s'il y a des fonctions imbriquées).
- Global: la portée globale du module courant.
- Built-in: la portée intégrée de Python.
S'il n'est pas trouvé localement, il sera recherché dans la portée locale englobante (par exemple, les fermetures) ; s'il n'est toujours pas trouvé, il sera recherché dans la portée globale, puis dans la portée intégrée.

g_count = 0 # 全局作用域
def outer():
o_count = 1 # 闭包函数外的函数中
def inner():
i_count = 2 # 局部作用域
La portée intégrée est implémentée via un module standard nommé builtin, mais le nom de variable lui-même n'est pas placé dans la portée intégrée, vous devez donc importer ce fichier pour l'utiliser. Dans Python 3.0, vous pouvez utiliser le code suivant pour voir exactement quelles variables sont prédéfinies :
>>> import builtins >>> dir(builtins)
En Python, seuls les modules, les classes et les fonctions (def, lambda) introduisent de nouvelles portées. Les autres blocs de code (tels que if/elif/else, try/except, for/while, etc.) n'introduisent pas de nouvelles portées. Autrement dit, les variables définies à l'intérieur de ces instructions sont également accessibles de l'extérieur, comme dans le code suivant :
>>> if True: ... msg = 'I am from Example' ... >>> msg 'I am from Example' >>>
Dans l'exemple, la variable msg est définie dans un bloc d'instruction if, mais elle est toujours accessible de l'extérieur.
Si msg est défini à l'intérieur d'une fonction, alors c'est une variable locale et il n'est pas accessible de l'extérieur :
>>> def test(): ... msg_inner = 'I am from Example' ... >>> msg_inner Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'msg_inner' is not defined >>>
D'après le message d'erreur, il est indiqué que msg_inner n'est pas défini et ne peut pas être utilisé, car il s'agit d'une variable locale et elle ne peut être utilisée qu'à l'intérieur de la fonction.
Variables globales et locales
Les variables définies à l'intérieur d'une fonction ont une portée locale, et celles définies à l'extérieur d'une fonction ont une portée globale.
Les variables locales ne sont accessibles qu'à l'intérieur de la fonction où elles sont déclarées, tandis que les variables globales sont accessibles dans tout le programme.
Les variables déclarées à l'intérieur d'une fonction ne sont valides que dans la portée de la fonction. Lorsque la fonction est appelée, ces variables internes sont ajoutées à la portée interne de la fonction et n'affectent pas les variables du même nom à l'extérieur de la fonction, comme dans l'exemple suivant :
Exemple (Python 3.0+)
La sortie de l'exemple ci-dessus est :
函数内是局部变量 : 30 函数外是全局变量 : 0
1. Variables globales: Les variables définies à l'extérieur d'une fonction sont accessibles dans tout le fichier. Les variables définies à l'extérieur d'une fonction sont visibles par toutes les fonctions, à moins qu'une variable locale du même nom ne soit définie à l'intérieur de la fonction.
Exemple
def my_function():
print(x) # Peut accéder à la variable globale x
my_function() # Affiche 10
2. Variables locales: Les variables définies à l'intérieur d'une fonction ne sont valides qu'à l'intérieur de la fonction et ne sont pas accessibles de l'extérieur. Les variables locales ont une priorité plus élevée que les variables globales, donc si une variable locale et une variable globale ont le même nom, la variable locale est utilisée à l'intérieur de la fonction.
Exemple
x = 5 # Variable locale
print(x) # Accès à la variable locale x
my_function() # Affiche 5
print(x) # Erreur : NameError: name 'x' is not defined
Les mots-clés global et nonlocal
Lorsqu'une portée interne veut modifier une variable d'une portée externe, les mots-clés global et nonlocal sont nécessaires.
L'exemple suivant modifie la variable globale num :
Exemple (Python 3.0+)
La sortie de l'exemple ci-dessus est :
1 123 123
Si vous souhaitez modifier une variable dans une portée imbriquée (portée englobante, la portée externe non globale), vous avez besoin du mot-clé nonlocal, comme dans l'exemple suivant :
Exemple (Python 3.0+)
La sortie de l'exemple ci-dessus est :
100 100
Il y a aussi un cas particulier. Supposons que le code suivant soit exécuté :
Exemple (Python 3.0+)
Lorsque le programme ci-dessus est exécuté, le message d'erreur est le suivant :
Traceback (most recent call last):
File "test.py", line 7, in <module>
test()
File "test.py", line 5, in test
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
Le message d'erreur est une erreur de référence à une portée locale, car a dans la fonction test utilise la variable locale, qui n'est pas définie et ne peut pas être modifiée.
Modifiez a pour en faire une variable globale :
Exemple
La sortie d'exécution est :
Il peut également être transmis via les paramètres de fonction :
Exemple (Python 3.0+)
La sortie d'exécution est :
Résumé
- Variables globalesDéfinies à l'extérieur d'une fonction, accessibles dans tout le fichier.
- Variables localesDéfinies à l'intérieur d'une fonction, accessibles uniquement au sein de la fonction.
- Utiliser
globalVous pouvez modifier des variables globales à l'intérieur d'une fonction. - Utiliser
nonlocalVous pouvez modifier les variables de la fonction externe à l'intérieur de fonctions imbriquées.