¿Es posible modificar una variable en Python que está en un alcance externo (cerrado), pero no global?
Considere este ejemplo:
def A():
b = 1
def B():
# I can access 'b' from here.
print(b)
# But can i modify 'b' here?
B()
A()
Para el código de la B
función, la variable b
está en un ámbito envolvente (externo) no global. ¿ Cómo puedo modificar b
desde dentro B
? Obtengo un UnboundLocalError
si lo intento directamente y usarlo global
no soluciona el problema ya que b
no es global.
Python implementa un alcance léxico, no dinámico , como casi todos los lenguajes modernos. Las técnicas aquí no permitirán el acceso a las variables de la persona que llama, a menos que la persona que llama también sea una función adjunta, porque la persona que llama no está dentro del alcance. Para obtener más información sobre este problema, consulte ¿Cómo puedo acceder a las variables de la persona que llama, incluso si no es un alcance cerrado (es decir, implementar un alcance dinámico)? .
En Python 3 , use la nonlocal
palabra clave :
La
nonlocal
declaración hace que los identificadores enumerados hagan referencia a variables previamente vinculadas en el ámbito adjunto más cercano, excluyendo los globales. Esto es importante porque el comportamiento predeterminado para el enlace es buscar primero en el espacio de nombres local. La declaración permite que el código encapsulado vuelva a vincular variables fuera del alcance local además del alcance global (módulo).
def foo():
a = 1
def bar():
nonlocal a
a = 2
bar()
print(a) # Output: 2
En Python 2 , use un objeto mutable (como una lista o dict) y mute el valor en lugar de reasignar una variable:
def foo():
a = []
def bar():
a.append(1)
bar()
bar()
print a
foo()
Salidas:
[1, 1]
Puede utilizar una clase vacía para contener un ámbito temporal. Es como el mutable pero un poco más bonito.
def outer_fn():
class FnScope:
b = 5
c = 6
def inner_fn():
FnScope.b += 1
FnScope.c += FnScope.b
inner_fn()
inner_fn()
inner_fn()
Esto produce el siguiente resultado interactivo:
>>> outer_fn()
8 27
>>> fs = FnScope()
NameError: name 'FnScope' is not defined