Python 究竟如何评估类属性?我偶然发现了一个我想解释的有趣的怪癖(在 Python 2.5.2 中)。
我有一个类,其中一些属性是根据其他先前定义的属性定义的。当我尝试使用生成器对象时,Python 会抛出错误,但如果我使用普通的列表推导式,则没有问题。
这是精简的示例。请注意,唯一的区别是Brie
使用生成器表达式,而Cheddar
使用列表推导。
# 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]
(我的实际情况更复杂,我正在创建一个字典,但这是我能找到的最小示例。)
我唯一的猜测是列表推导是在该行计算的,但是生成器表达式是在类结束之后计算的,此时范围已经改变。但是我不确定为什么生成器表达式不充当闭包并将对 base 的引用存储在行的范围内。
这有什么原因吗?如果是这样,我应该如何考虑类属性的评估机制?