Ответ 1
Краткий ответ и обходное решение
У вас есть ограничение на отладчик. Выражения, введенные в отладчик, не могут использовать значения, не связанные с локальным охватом, поскольку отладчик не может создать необходимые закрытия.
Вместо этого вы можете создать функцию для запуска генератора, создав одновременно новую область:
def _test(baz, lengths):
return all(0 < size < baz for size in lengths)
_test(len(self.dataDict), lengths)
Обратите внимание, что это относится также к понятию набора и словаря, а в Python 3 - к пониманию списка.
Долгий ответ, почему это происходит
Выражения генератора (и определения списка, dict и Python 3) запускаются в новом, вложенном пространстве имен. Имя baz
в выражении генератора не является локальным в этом пространстве имен, поэтому Python должен найти его где-то в другом месте. Во время компиляции Python определяет, откуда это имя. Он будет искать из областей, доступных компилятору, и если совпадений нет, объявляет имя глобальным.
Вот два генераторных выражения для иллюстрации:
def function(some_iterable):
gen1 = (var == spam for var in some_iterable)
ham = 'bar'
gen2 = (var == ham for var in some_iterable)
return gen1, gen2
Имя spam
не найдено в родительской области, поэтому компилятор отмечает это как глобальное:
>>> dis.dis(function.__code__.co_consts[1]) # gen1
2 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (var)
9 LOAD_FAST 1 (var)
12 LOAD_GLOBAL 0 (spam)
15 COMPARE_OP 2 (==)
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Код операции в индексе 12 использует LOAD_GLOBAL
для загрузки имени spam
.
Имя ham
находится в области видимости функции, поэтому компилятор генерирует байт-код для поиска имени как закрытия из функции. В то же время имя ham
отмечено как закрытие; переменная обрабатывается по-разному кодом, сгенерированным для function
, поэтому вы можете ссылаться на него, когда функция вернулась.
>>> dis.dis(function.__code__.co_consts[3]) # gen2
4 0 LOAD_FAST 0 (.0)
>> 3 FOR_ITER 17 (to 23)
6 STORE_FAST 1 (var)
9 LOAD_FAST 1 (var)
12 LOAD_DEREF 0 (ham)
15 COMPARE_OP 2 (==)
18 YIELD_VALUE
19 POP_TOP
20 JUMP_ABSOLUTE 3
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
>>> function.__code__.co_cellvars # closure cells
('ham',)
Имя ham
загружается кодом операции LOAD_DEREF
, а объект-код функции указывает это имя как закрытие. Когда вы разбираете function
, вы можете найти среди других байт-код:
>>> dis.dis(function)
# ....
4 22 LOAD_CLOSURE 0 (ham)
25 BUILD_TUPLE 1
28 LOAD_CONST 3 (<code object <genexpr> at 0x1074a87b0, file "<stdin>", line 4>)
31 MAKE_CLOSURE 0
34 LOAD_FAST 0 (some_iterable)
37 GET_ITER
38 CALL_FUNCTION 1
41 STORE_FAST 2 (gen2)
# ...
где байт-коды LOAD_CLOSURE
и MAKE_CLOSURE
создают закрытие для ham
, которое будет использоваться объектом кода генератора.
При выполнении произвольных выражений в отладчике компилятор не имеет доступа к пространству имен, которое вы отлаживаете. Что еще более важно, он не может изменить это пространство имен, чтобы создать закрытие. Таким образом, вы не можете использовать ничего, кроме глобалов, в выражениях генератора.