¿Cómo exactamente Python evalúa los atributos de clase? Me encontré con una peculiaridad interesante (en Python 2.5.2) que me gustaría explicar.Evaluación de atributos de clase y generadores
Tengo una clase con algunos atributos que se definen en términos de otros atributos previamente definidos. Cuando intento usar un objeto generador, Python arroja un error, pero si uso una comprensión simple de la lista ordinaria, no hay problema.
Aquí está el ejemplo recortado. Tenga en cuenta que la única diferencia es que Brie
usa una expresión de generador, mientras que Cheddar
usa una lista de comprensión.
# Using a generator expression as the argument to list() fails
>>> class Brie :
... base = 2
... powers = list(base**i for i in xrange(5))
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in Brie
File "<stdin>", line 3, in <genexpr>
NameError: global name 'base' is not defined
# Using a list comprehension works
>>> class Cheddar :
... base = 2
... powers = [base**i for i in xrange(5)]
...
>>> Cheddar.powers
[1, 2, 4, 8, 16]
# Using a list comprehension as the argument to list() works
>>> class Edam :
... base = 2
... powers = list([base**i for i in xrange(5)])
...
>>> Edam.powers
[1, 2, 4, 8, 16]
(Mi caso real fue más complicado, y yo estaba creando un diccionario, pero este es el ejemplo mínimo que pude encontrar.)
Mi única suposición es que las listas por comprensión se calculan en esa línea , pero las expresiones del generador se calculan después del final de la clase, en cuyo punto el alcance ha cambiado. Pero no estoy seguro de por qué la expresión del generador no actúa como cierre y almacena la referencia a la base en el alcance de la línea.
¿Hay alguna razón para esto? De ser así, ¿cómo debería pensar en la mecánica de evaluación de los atributos de clase?