objeto - Reglas de alcance de clase de Python
instancia python (2)
Primero se enfoca en el caso de un cierre - una función dentro de una función:
x = "xtop"
y = "ytop"
def func():
x = "xlocal"
y = "ylocal"
def inner():
# global y
print(x)
print(y)
y=''inner y''
print(y)
inner()
Tenga en cuenta el comentario global
en inner
Si ejecuta esto, replica el UnboundLocalError
que obtuvo. ¿Por qué?
Ejecutar dis.dis en él:
>>> import dis
>>> dis.dis(func)
6 0 LOAD_CONST 1 (''xlocal'')
3 STORE_DEREF 0 (x)
7 6 LOAD_CONST 2 (''ylocal'')
9 STORE_FAST 0 (y)
8 12 LOAD_CLOSURE 0 (x)
15 BUILD_TUPLE 1
18 LOAD_CONST 3 (<code object inner at 0x101500270, file "Untitled 3.py", line 8>)
21 LOAD_CONST 4 (''func.<locals>.inner'')
24 MAKE_CLOSURE 0
27 STORE_FAST 1 (inner)
14 30 LOAD_FAST 1 (inner)
33 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
36 POP_TOP
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
Tenga en cuenta el modo de acceso diferente de x
vs y
dentro de func
. El uso de y=''inner y''
dentro de inner
ha creado UnboundLocalError
Ahora descomentar global y
dentro de inner
. Ahora, sin ambigüedades, crea y
para ser la versión global más importante hasta que renuncies como y=''inner y''
Con global
comentarios, imprime:
xlocal
ytop
inner y
Puede obtener un resultado más sensible con:
x = "xtop"
y = "ytop"
def func():
global y, x
print(x,y)
x = "xlocal"
y = "ylocal"
def inner():
global y
print(x,y)
y = ''inner y''
print(x,y)
inner()
Huellas dactilares:
xtop ytop
xlocal ylocal
xlocal inner y
El análisis de la clase de cierre se complica por las variables instancia contra clase y qué / cuándo se ejecuta una clase simple (sin instancia).
La línea inferior es la misma: si hace referencia a un nombre fuera del espacio de nombres local y luego lo asigna localmente, obtendrá un resultado sorprendente.
El ''arreglo'' es el mismo: use la palabra clave global:
x = "xtop"
y = "ytop"
def func():
global x, y
x = "xlocal"
y = "ylocal"
class Inner:
print(x, y)
y = ''Inner_y''
print(x, y)
Huellas dactilares:
xlocal ylocal
xlocal Inner_y
Puede leer más sobre las reglas de alcance de Python 3 en PEP 3104
EDITAR: Parece que esto es un "error" muy antiguo o, en realidad, característica. Ver, por ejemplo, este correo
Estoy tratando de entender las reglas de alcance de Python. Más precisamente, pensé que los entendía pero luego encontré este código here :
x = "xtop"
y = "ytop"
def func():
x = "xlocal"
y = "ylocal"
class C:
print(x)
print(y)
y = 1
func()
En Python 3.4 la salida es:
xlocal
ytop
Si sustituyo la clase interna por una función, entonces razonablemente se le da a UnboundLocalError
. ¿Podría explicarme por qué se comporta de esta forma tan extraña con las clases y cuál es la razón de tal elección de reglas de alcance?
TL; DR : Este comportamiento ha existido desde Python 2.1 PEP 227: Ámbitos anidados , y era conocido en ese entonces. Si se asigna un nombre dentro de un cuerpo de clase (como y
), entonces se asume que es una variable local / global; Si no está asignado a ( x
), entonces también puede apuntar a una celda de cierre. Las variables léxicas no se muestran como nombres locales / globales para el cuerpo de la clase.
En Python 3.4, dis.dis(func)
muestra lo siguiente:
>>> dis.dis(func)
4 0 LOAD_CONST 1 (''xlocal'')
3 STORE_DEREF 0 (x)
5 6 LOAD_CONST 2 (''ylocal'')
9 STORE_FAST 0 (y)
6 12 LOAD_BUILD_CLASS
13 LOAD_CLOSURE 0 (x)
16 BUILD_TUPLE 1
19 LOAD_CONST 3 (<code object C at 0x7f083c9bbf60, file "test.py", line 6>)
22 LOAD_CONST 4 (''C'')
25 MAKE_CLOSURE 0
28 LOAD_CONST 4 (''C'')
31 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
34 STORE_FAST 1 (C)
37 LOAD_CONST 0 (None)
40 RETURN_VALUE
LOAD_BUILD_CLASS
carga los builtins.__build_class__
en la pila; esto se llama con los argumentos __build_class__(func, name)
; donde func
es el cuerpo de la clase, y el name
es ''C''
. El cuerpo de la clase es la constante # 3 para la función func
:
>>> dis.dis(func.__code__.co_consts[3])
6 0 LOAD_NAME 0 (__name__)
3 STORE_NAME 1 (__module__)
6 LOAD_CONST 0 (''func.<locals>.C'')
9 STORE_NAME 2 (__qualname__)
7 12 LOAD_NAME 3 (print)
15 LOAD_CLASSDEREF 0 (x)
18 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
21 POP_TOP
8 22 LOAD_NAME 3 (print)
25 LOAD_NAME 4 (y)
28 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
31 POP_TOP
9 32 LOAD_CONST 1 (1)
35 STORE_NAME 4 (y)
38 LOAD_CONST 2 (None)
41 RETURN_VALUE
Dentro del cuerpo de la clase, se accede a x
con LOAD_CLASSDEREF
(15) mientras que y
se carga con LOAD_NAME
(25). LOAD_CLASSDEREF
es un código de operación de Python 3.4+ para cargar valores desde celdas de cierre específicamente dentro de cuerpos de clase (en versiones anteriores, se utilizó el LOAD_DEREF
genérico); LOAD_NAME
es para cargar valores de locales y luego globales . Sin embargo, las celdas de cierre no aparecen ni como locales ni como globales.
Ahora, debido a que el nombre y
se almacena dentro del cuerpo de la clase (35), se usa de manera consistente como no una celda de cierre sino un nombre local / global. Las celdas de cierre no aparecen como variables locales para el cuerpo de la clase.
Este comportamiento se ha cumplido desde la implementación de PEP 227: ámbitos anidados . Y en ese entonces, BDFL declaró que esto no debería ser arreglado, y así lo ha sido por más de 13 años.
El único cambio desde PEP 227 es la adición de nonlocal
en Python 3; si uno lo usa dentro del cuerpo de la clase, el cuerpo de la clase puede establecer los valores de las celdas dentro del alcance que contiene:
x = "xtop"
y = "ytop"
def func():
x = "xlocal"
y = "ylocal"
class C:
nonlocal y # y here now refers to the outer variable
print(x)
print(y)
y = 1
print(y)
print(C.y)
func()
La salida ahora es
xlocal
ylocal
1
Traceback (most recent call last):
File "test.py", line 15, in <module>
func()
File "test.py", line 13, in func
print(C.y)
AttributeError: type object ''C'' has no attribute ''y''
Es decir, print(y)
lea el valor de la celda y
del ámbito que contiene, y y = 1
establezca el valor en esa celda; en este caso, no se creó ningún atributo para la clase C