La portée variable et le mécanisme de référencement de Python sont étonnamment peu intuitifs, et les débutants peuvent tomber dans le piège. Mais une fois que vous avez appris les règles, ce n'est pas si compliqué. Voici quelques points pour vous aider à comprendre cela.
Pour chaque question, répondez à ** ce qui est produit ou si une erreur est générée **. L'environnement d'exécution est Python 3. Le problème difficile (ou plutôt maniaque) est que le titre est rouge </ font>.
x = 1
if True:
x = 2
print(x)
2
En Python, l'instruction ʻif` ne forme pas de portée. Par conséquent, «x» dans l'instruction «if» est la même variable que le «x» extérieur.
for i in range(10):
x = i * 2
print(i, x)
9 18
Comme ʻif, l'instruction
forne forme pas de portée, donc les variables de boucle et les variables définies en interne sont accessibles après l'instruction
for`.
ls = [x * 2 for x in range(10)]
print(x)
(print(x)À l'endroit)
NameError: name 'x' is not defined
Lorsque la compréhension de liste est exécutée, une nouvelle portée est créée et des variables de boucle y sont définies. Par conséquent, «X» n'est pas accessible à partir de «print (x)» existant dans la portée externe.
funs = []
for i in range(5):
def f():
print(i)
funs.append(f)
for fun in funs:
fun()
4
4
4
4
4
La variable externe ʻi est référencée depuis l'intérieur de la fonction
f, mais la valeur de ʻi
au moment où ** print (i)
est exécuté est utilisée **. Les cinq f
s sont exécutés après l'instruction for
, à quel point ʻi est égal à
4, donc ils affichent tous
4`.
La même chose se produit avec la notation d'inclusion de liste.
x = 0
def f():
x = 1
f()
print(x)
0
Puisque le bloc [^ block] formé par la fonction f
a une ** instruction d'affectation ** de x = 1
, une nouvelle variable de x
sera créée dans la portée de ce bloc. Autrement dit, le «x» de niveau supérieur n'est pas modifié par «f».
[^ block]: block est un ensemble de code correspondant à une portée. , Une portée est formée pour chaque bloc. Ce sont les fonctions, les modules (c'est-à-dire le niveau supérieur) et les définitions de classe qui forment les blocs.
x = 0
def f():
print(x)
x = 1
f()
(print(x)À l'endroit)
UnboundLocalError: local variable 'x' referenced before assignment
Semblable au problème précédent, le bloc formé par la fonction f
a une ** instruction d'affectation ** qui dit x = 1
, donc la portée est x avant ** avant que le bloc ne soit exécuté. Une variable appelée x
est créée. Cependant, lorsque print (x)
est exécuté, x
n'est pas lié, donc une exception est levée.
x = 0
def f():
x += 1
f()
print(x)
(print(x)À l'endroit)
UnboundLocalError: local variable 'x' referenced before assignment
Puisque «+ =» est également considéré comme une instruction d'affectation, la variable «x» est créée dans le bloc formé par «f» comme dans le problème précédent. Cependant, lorsque «x + = 1» est exécuté, la valeur de «x» n'existe pas, donc une exception est levée.
Vous devez utiliser global
ou nonlocal
pour changer la valeur des variables dans la portée externe.
x = 0
def f():
if False:
x = 1
print(x)
f()
(print(x)À l'endroit)
UnboundLocalError: local variable 'x' referenced before assignment
Puisque l'instruction ʻif ne forme pas un bloc, il y a une instruction d'affectation à
xdans le bloc formé par
f comme dans le problème précédent, et la variable
x` est créée. Cependant, en réalité, une valeur n'est pas affectée à «x», donc une exception se produit.
x = 0
def f():
del x
f()
(À la place de del x)
UnboundLocalError: local variable 'x' referenced before assignment
En fait, l'instruction del
a pour effet de créer une variable dans le bloc, tout comme l'instruction d'affectation. Par conséquent, la variable «x» est créée dans le bloc formé par «f», mais une exception se produit car «del x» est exécuté sans que la valeur de «x» existe.
La syntaxe qui a pour effet de créer des variables de cette manière est l'instruction d'affectation, l'instruction del
, l'instruction for
, la définition de classe, la définition de fonction, l'instruction ʻimport et les
avec et ʻexcept
ʻas`.
x = 0
def f():
def g():
print(x)
x = 1
g()
f()
1
Lorsque «g» est exécuté, «1» est affiché car «x» existe dans la portée externe («f») et la valeur est «1».
x = 0
def f():
x = 1
del x
def g():
print(x)
g()
f()
(print(x)À l'endroit)
NameError: free variable 'x' referenced before assignment in enclosing scope
Même si del x
est exécuté, x
continue d'exister dans la portée de f
(seule la valeur disparaît). Par conséquent, «x» dans «g» fait référence à «x» défini par «f». Mais ce «x» n'a aucune valeur, donc une exception se produit.
Pour la même raison, les deux codes suivants donnent le même résultat.
x = 0
def f():
x = 1
def g():
print(x)
del x
g()
f()
x = 0
def f():
def g():
print(x)
x = 1
del x
g()
f()
x = 1
def f():
x = 2
try:
raise Exception()
except Exception as x:
pass
def g():
print(x)
g()
f()
(print(x)À l'endroit)
NameError: free variable 'x' referenced before assignment in enclosing scope
Lorsqu'une exception se produit dans l'instruction try
et que la clause ʻexcept est exécutée, la valeur spécifiée dans ʻas
est ** supprimée ** comme dans del
**. Par conséquent, lorsque g
est exécuté, x
dans f
existe mais n'a pas de valeur, donc une exception se produit.
Si la clause ʻexcept` n'est pas exécutée, la variable correspondante n'est pas supprimée.
x = 1
class C:
x = 2
def f():
print(x)
f()
1
Le code de la définition de classe est spécial par rapport à la portée, et les variables qui y sont définies (variables de classe) ne sont accessibles qu'à partir de cette portée, ** pas directement à partir des fonctions (c'est-à-dire des méthodes) dans la définition de classe **.
x = 0
def f():
x = 1
def g():
print(eval("x"))
g()
f()
0
Ceci est un problème avec le comportement (non intuitif) de la fonction ʻeval. Les seules variables accessibles à partir du code exécuté par la fonction ʻeval
sont en fait ** "variables globales" et "variables définies dans le bloc où ʻeval est exécuté **", et les variables définies entre elles Est inaccessible. Dans le code actuel, les variables (non intégrées) auxquelles on peut accéder à partir du code passé à la fonction ʻeval
sont les variables (pas même une) définies dans le "x" et "g" sur la première ligne. Par conséquent, le «x» de niveau supérieur est référencé et «0» est affiché.
La fonction ʻexec` se comporte de la même manière.
Recommended Posts