How exactly does Python evaluate class attributes? I've stumbled across an interesting quirk (in Python 2.5.2) that I'd like explained.
I have a class with some attributes that are defined in terms of other, previously defined attributes. When I try using a generator object, Python throws an error, but if I use a plain ordinary list comprehension, there's no problem.
Here's the pared-down example. Note that the only difference is that Brie
uses a generator expression, while Cheddar
uses a list comprehension.
# 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]
(My actual case was more complicated, and I was creating a dict, but this is the minimum example I could find.)
My only guess is that the list comprehensions are computed at that line, but the generator expressions are computed after the end of the class, at which point the scope has changed. But I'm not sure why the generator expression doesn't act as a closure and store the reference to base in the scope at the line.
Is there a reason for this, and if so, how should I be thinking of the evaluation mechanics of class attributes?