Аргументы аргументов, недоступные в диктовке

Почему доступ к аргументам функции с eval в понимании dict не выполняется?

 ARGS1 = ('a1', 'b1') def foo1(a1, b1): return {arg:eval(arg) for arg in ARGS1} print foo1("A1", "B1") # NameError: name 'a1' is not defined 

То же самое в понимании списка прекрасно:

 ARGS2 = ('a2', 'b2') def foo2(a2, b2): return [eval(arg) for arg in ARGS2] print foo2("A2", "B2") # OK, print: ['A2', 'B2'] 

Он также хорошо работает без функции:

 ARGS3 = ('a3', 'b3') a3, b3 = ("A3", "B3") print {arg:eval(arg) for arg in ARGS3} # OK, print: ['A3', 'B3'] 

Или, если определены глобальные значения:

 ARGS4 = ('a4', 'b4') a4, b4 = ("A4", "B4") def foo4(): return [eval(arg) for arg in ARGS4] print foo4() # OK, print: ['A4', 'B4'] 

Это действительно похоже на ошибку, но, может быть, я что-то пропустил.

(EDITED включает примеры без функции и с глобалями)

Понятие распознавания выполняется в новой области, как функция.

Таким образом, локаторы выражения ограничены только именами, указанными в цикле, в данном случае arg . Локальные родительские функции не учитываются, поскольку закрытие связано только во время компиляции. Имена, на которые ссылается eval() не могут использовать закрытие.

Не работает также следующее:

 >>> ARGS = ('a', 'b') >>> def bar(a, b): ... def foo(): ... for arg in ARGS: ... eval(arg) ... return foo ... >>> print bar("A", "B")() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 4, in foo File "<string>", line 1, in <module> NameError: name 'a' is not defined 

Имена a и b недоступны для внутренней функции foo если компилятор не определил, что эта функция действительно нуждается в доступе к ним:

 >>> def bar2(a, b): ... def foo(): ... a, b ... for arg in ARGS: ... eval(arg) ... return foo ... >>> print bar2("A", "B")() None >>> print bar2("A", "B").func_closure (<cell at 0x1051bac20: str object at 0x104613328>, <cell at 0x1051bacc8: str object at 0x1045971e8>) >>> print bar2("A", "B").__code__.co_freevars ('a', 'b') 

Здесь строка a, b может относиться только к родительским областям видимости (они не назначены непосредственно в foo() ), поэтому компилятор создал для них закрытие, и имена стали доступными как locals внутри foo() .

В списках Python 2 нет собственного пространства имен, упущенное исправление в Python 3 и не расширенное до dict и устанавливающее понимание. См. Pindon list постижения повторных имен даже после понимания. Это правильно?