Почему eval не может найти переменную, определенную во внешней функции? - PullRequest
0 голосов
/ 12 сентября 2018

Я знаю, что использование eval() обычно означает плохой код, но я наткнулся на странное поведение функции eval() во внутренних функциях, которое я не мог понять.Если мы напишем:

def f(a):
    def g():
        print(eval('a'))
    return g()

Запуск f(1), в этом случае выдается NameError, утверждая, что a не определено.Однако, если мы определим

def f(a):
    def g():
        b = a + 1
        print(eval('a'))
    return g()

, тогда выполняется f(1) печатает 1.

Что-то происходит с локальными и глобальными переменными, которые я не совсем понимаю.Является ли a только локальной переменной в g(), когда она «используется» для чего-то?Что здесь происходит?

Ответы [ 2 ]

0 голосов
/ 12 июня 2019

Похоже, что eval () может искать переменные только в локальной (здесь g) или глобальной, но не в родительской среде (здесь f).Обходной путь - установить переменную как глобальную.

def f(a):    
    global b #note, can not use "global a" directly,  will get error:"name 'a' is parameter and global"
    b=a
    def g():
        print(eval('b'))
    return g()
f(1)

выход: 1

0 голосов
/ 12 сентября 2018

Короче говоря, поскольку eval предназначен для динамической оценки, интерпретатор не может знать, что он должен добавить a к локальной области действия g. Для эффективности интерпретатор не будет добавлять ненужные переменные в dict локальных переменных.

Из документа на eval:

Аргумент выражения анализируется и оценивается как выражение Python (технически говоря, список условий) с использованием глобальных и локальных словарей в качестве глобального и локального пространства имен.

Это означает, что функции eval(expression) будут использовать globals() в качестве глобальной области видимости по умолчанию и locals() в качестве локальной области видимости, если ничего не указано.

Хотя в первом примере a ни в одном.

def f(a):
    print("f's locals:", locals())
    def g():
        print("g's locals:", locals())
        print(eval('a'))
    return g()

f(1)

Действительно, поскольку интерпретатор не видит ссылки на a при анализе тела g, он не добавляет его к своим локальным переменным.

Чтобы это работало, вам нужно указать nonlocal a в g.

выход

f's locals: {'a': 1}
g's locals: {}
Traceback ...
...
NameError: name 'a' is not defined

Во втором примере a находится в g локальных переменных, так как используется в области действия.

def f(a):
    print("f's locals:", locals())
    def g():
        print("g's locals:", locals())
        b = a + 1
        print("g's locals after b = a + 1:", locals())
        print(eval('a'))
    return g()

f(1)

выход

f's locals: {'a': 1}
g's locals: {'a': 1}
g's locals after b = a + 1: {'a': 1, 'b': 2}
1
...