Как именно 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]
(Мой фактический случай был более сложным, и я создавал dict, но это минимальный пример, который я мог найти.)
Мое единственное предположение состоит в том, что методы подсчета списков вычисляются в этой строке, но выражения генератора вычисляются после окончания класса, после чего область изменений изменилась. Но я не уверен, почему выражение генератора не действует как замыкание и сохраняет ссылку на базу в области на линии.
Есть ли причина для этого, и если да, то как я должен думать о механизме оценки атрибутов класса?