le bloc crée une variable x donc on retire x de la table
Ha mais non, on supprime rien.
C'est plutôt que la variable x dans le namespace de la class bar "masque" la variable x dans le namespace de foo.
Le fonctionnement global est celui ci:
Lors de la définition d'une fonction (ou d'une class ici), un "scope" (local) est créé.
Lors de la résolution de nom (la recherche de l’objet qui correspond à x), on cherche d'abord dans ce scope local. Si on le trouve pas et si la définition de la fonction à lieu dans un scope (par exemple à l'intérieur de l’exécution de foo()), on cherche dans ce scope "parent". Si on le trouve toujours pas, on remonte à nouveau (si on peut). Enfin, on arrive au scope global (celui du module) et si on trouve toujours pas, on arrête avec une exception NameError.
La subtilité, c'est qu'on attend pas de faire un x = 1 pour créer la variable x dans son scope. À la définition de la fonction, python "sait" qu'on va avoir besoin d'une variable x et donc il crée le slot (vide) dans le scope dès le début de l’exécution.
Donc lors de la résolution de nom, il trouve x dans le scope local et donc arrête de chercher dans le scopes parents. Mais comme x n'est pas encore initialisé, bam !
Donc c'est bien l'existence de la variable x dans le scope local qui masque x dans les scopes parent même si l'initialisation de x a lieu après la ligne qui plante.
La résolution de nom à lieu à l’exécution du code, ce qui peut amener des surprises :
deffoo():foriinrange(3):defbar():print(i)yieldbar# Affiche 0, 1 et 2forfinfoo():f()# Affiche 2, 2, 2functions=list(foo())forfinfunctions:# Lors de l'appel à `f`, la boucle dans foo a fini et donc i vaut tout le temps 2f()
Si on veut forcer la résolution des nom à la définition, il faut lire la valeur à la définition:
deffoo():foriinrange(3):defbar(i=i):# i est dans le scope local (c'est un argument) et ça valeur par défaut# est la valeur de i (dans foo) *au moment de la définition de bar*print(i)yieldbar# Affiche 0, 1 et 2functions=list(foo())forfinfunctions:f()
Le mot clé nonlocal permet de dire à python de ne pas créer de slot dans le scope local mais d'utiliser celui du scope parent (et seulement celui là). global fait la même chose mais dit d'utiliser le scope global :
deffoo():x=5defbar():nonlocalxx=6print(x)yieldbardefbaz():print(x)yieldbaz# Affiche 6 et 6forfinfoo():f()
[^] # Re: Et pourtant c'est simple
Posté par GaMa (site web personnel) . En réponse au journal Quizz Python : esp[èa]ce de nom. Évalué à 7. Dernière modification le 09 mars 2023 à 15:03.
Ha mais non, on supprime rien.
C'est plutôt que la variable
xdans le namespace de la classbar"masque" la variablexdans le namespace defoo.Le fonctionnement global est celui ci:
Lors de la définition d'une fonction (ou d'une class ici), un "scope" (local) est créé.
Lors de la résolution de nom (la recherche de l’objet qui correspond à
x), on cherche d'abord dans ce scope local. Si on le trouve pas et si la définition de la fonction à lieu dans un scope (par exemple à l'intérieur de l’exécution defoo()), on cherche dans ce scope "parent". Si on le trouve toujours pas, on remonte à nouveau (si on peut). Enfin, on arrive au scope global (celui du module) et si on trouve toujours pas, on arrête avec une exceptionNameError.La subtilité, c'est qu'on attend pas de faire un
x = 1pour créer la variable x dans son scope. À la définition de la fonction, python "sait" qu'on va avoir besoin d'une variable x et donc il crée le slot (vide) dans le scope dès le début de l’exécution.Donc lors de la résolution de nom, il trouve
xdans le scope local et donc arrête de chercher dans le scopes parents. Mais comme x n'est pas encore initialisé, bam !Donc c'est bien l'existence de la variable
xdans le scope local qui masquexdans les scopes parent même si l'initialisation dexa lieu après la ligne qui plante.Ça donne des trucs rigolo :
nonlocalpermet de dire à python de ne pas créer de slot dans le scope local mais d'utiliser celui du scope parent (et seulement celui là).globalfait la même chose mais dit d'utiliser le scope global :Matthieu Gautier|irc:starmad