Проще говоря: передача заполненного каталога locals
не меняет способ, которым python анализирует код функции и решает, какие имена являются локальными, а какие глобальными.
Локальные имена - это имена аргументов и имена, которые связаны внутри тела функции и явно не объявлены как глобальные или нелокальные.Здесь y
не является аргументом и не связан в теле функции (что в любом случае невозможно в lambda
), поэтому он помечается компилятором как глобальный.
Теперь эта глобальная и локальная среда - это те, которые используются для оценки самого выражения (здесь полное выражение «лямбда: печать (у)»), а не «локальная среда для тела лямбды», так что даже если естьбыл способ сделать y
локальным по отношению к телу функции (подсказка: есть одна - но это не решит вашу проблему) это имя все равно не будет «автоматически» установлено на значение «y» в локальных данных, переданных dictдо eval
.
НО на самом деле это не проблема - функция, созданная eval("lambda: y", {"y":42})
, записывает глобальный запрос, переданный в eval
, и использует его вместо модуля / скрипта / любых глобальных переменных, поэтому она будет работать как положено:
Python 3.4.3 (default, Nov 28 2017, 16:41:13)
[GCC 4.8.4] on linux
>>> f = eval("lambda: y+2", {'y':2}, {})
>>> f()
4
>>> y = 42
>>> f()
4
Теперь у вас есть объяснение, я хочу добавить, что eval()
очень опасно и чаще всего существует гораздо лучшее решение, в зависимости от конкретной проблемы, с которой вы столкнулись.Пытаюсь решить.Вы не предоставили никакого контекста, поэтому невозможно сказать больше, но я должен сказать, что на самом деле мне трудно думать о конкретном сценарии использования такой вещи, как f = eval("lambda: whatever")
.