privados objeto metodos instancia importar herencia espaƱol definir como clases clase atributos python scoping

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