Вопрос:

eval globals и localals аргумент не работают, как ожидалось

python python-3.5

468 просмотра

2 ответа

2410 Репутация автора

Оператор eval'd, по-видимому, на самом деле не выполняется в среде с соответствующими глобальными и локальными объектами.

def f(x):
    return g(x)*3
def g(x):
    return x**2
funcs = {"f":f,"g":g}
del globals()['g'] # to keep them out of the global environment
del globals()['f']
eval("f(2)",globals(),funcs)

Ошибка:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "<stdin>", line 2, in f
NameError: name 'g' is not defined

Обновить:

Больше иллюстрации:

>>> exec("print(globals()['g'])",{**globals(),**funcs})
<function g at 0x7feb627aaf28>
>>> eval("f(2)",{**globals(),**funcs})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "<stdin>", line 2, in f
NameError: name 'g' is not defined

редактировать

Это не дубликат этого вопроса . Функция g не может найти, даже если она передана как глобальная.

Автор: Scott Источник Размещён: 11.04.2017 02:49

Ответы (2)


3 плюса

75604 Репутация автора

Проблему можно увидеть, посмотрев на байт-код, скомпилированный из
определения функции, f()используя dis.dis(f):

  7           0 LOAD_GLOBAL              0 (g)
              2 LOAD_FAST                0 (x)
              4 CALL_FUNCTION            1
              6 LOAD_CONST               1 (3)
              8 BINARY_MULTIPLY
             10 RETURN_VALUE

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

Один из способов заставить это работать - создать g()локальную функцию:

def f(x):
    def g(x):
        return x**2

    return g(x)*3

funcs = {"f": f}
del globals()['f'] # to keep it  out of the global environment
print(eval("f(2)", globals(), funcs))  # -> 12

Вот байт-код от пересмотренного f()для сравнения:

  8           0 LOAD_CONST               1 (<code object g at 0x00546288, file "test.py">)
              2 LOAD_CONST               2 ('f.<locals>.g')
              4 MAKE_FUNCTION            0
              6 STORE_FAST               1 (g)

 11           8 LOAD_FAST                1 (g)
             10 LOAD_FAST                0 (x)
             12 CALL_FUNCTION            1
             14 LOAD_CONST               3 (3)
             16 BINARY_MULTIPLY
             18 RETURN_VALUE
Автор: martineau Размещён: 11.04.2017 03:27

2 плюса

7948 Репутация автора

Решение

Когда вы определили f, он решил, что ссылка на gглобальный поиск имени. Кроме того, он сохранил ссылку на глобальную среду, действующую в момент определения (это то, что позволяет вам вызывать функции в других модулях, не лишая их первоначальных глобальных переменных).

Когда вы затем удалили g, вы принципиально сломались f- этот глобальный поиск gтеперь потерпит неудачу.

Глобальные / локальные параметры среды для вашего execвызова не оказывают никакого влияния на уже скомпилированную функцию f. Они влияют только на фактический текст , который вы exec'ed: "f(2)". Другими словами, единственный поиск имен, который фактически использует предоставленную вами среду, - это fсам по себе.

Автор: jasonharper Размещён: 11.04.2017 03:30
Вопросы из категории :
32x32