2015-10-13 3 views
2

Рассмотрим следующий фрагмент кода:Список и генератор постижений с классом variabes в условном операторе

class C(object): 
    a = 0 
    b = 1 
    seq = [1, 2, 4, 16, 17] 
    list_comp = [a if v%2 else b for v in seq] 
    gen_comp = (a if v%2 else b for v in seq) 

Код выше истолковано хорошо. Объект печати привязан к переменным класса приводит:

print C.list_comp # [0, 1, 1, 1, 0] 
print C.gen_comp # <generator object <genexpr> at ...> 

Sad часть - попытка получить значение из результатов генератора в NameError:

next(C.gen_comp) # NameError: global name 'a' is not defined 

Ожидаемое поведение должно быть похоже на список понимание - это должно дать 5 значения и поднять StopIteration на каждый следующий next() звонок.

Что здесь имеет значение? Как имена разрешаются в каждом случае и почему возникает несоответствие?

+0

Разница заключается в том, что теперь у понятий списка есть своя область видимости в Python 3, аналогичная выражению генератора. Также поясняется здесь: https://docs.python.org/2/reference/executionmodel.html –

ответ

1

Проблема заключается в том, что выражения генератора работают в собственном пространстве имен, следовательно, они не имеют доступа к именам в области видимости класса (переменные класса, такие как a или b).

Это дается в PEP 227 -

имен в области видимости класса не доступны. Имена разрешаются в самой внутренней области приложения. Если определение класса происходит в цепочке вложенных областей, процесс разрешения пропускает определения классов.

Следовательно, вы получаете NameError при попытке получить доступ к переменной класса в выражении генератора.

Способом обхода это будет доступ к требуемым значениям через класс, например C.a или C.b. Поскольку выражения внутри выражения генератора выполняются только при вызове на нем next(), мы можем быть уверены, что класс C был бы определен к тому времени. Пример -

>>> class C(object): 
...  a = 0 
...  b = 1 
...  seq = [1, 2, 4, 16, 17] 
...  list_comp = [a if v%2 else b for v in seq] 
...  gen_comp = (C.a if v%2 else C.b for v in seq) 
... 
>>> next(C.gen_comp) 
0 
>>> next(C.gen_comp) 
1 
>>> next(C.gen_comp) 
1 
>>> next(C.gen_comp) 
1 
>>> next(C.gen_comp) 
0 

Примечания, та же самая проблема возникает в список понимание в Python 3.x, так как в Python 3.x, списочные имеют свои собственные области. См. Accessing class variables from a list comprehension in the class definition для более подробной информации.

Смежные вопросы