如果函数是在 exec 代码之外定义的(因此已经绑定到 different __globals__
),是否可以从函数内访问 exec 提供的全局字典?
换句话说,有没有办法让下面的例子工作?
def f():
log("Hi")
exec('f()', {'f': f, 'log': print})
一般来说,是否可以替换__globals__
函数?
如果函数是在 exec 代码之外定义的(因此已经绑定到 different __globals__
),是否可以从函数内访问 exec 提供的全局字典?
换句话说,有没有办法让下面的例子工作?
def f():
log("Hi")
exec('f()', {'f': f, 'log': print})
一般来说,是否可以替换__globals__
函数?
这是一件很奇怪的事情,但它是可行的。
您的 exec 调用在提供的全局变量中执行语句f()
。它不执行提供的全局变量中的主体。f
提供的全局变量在错误的堆栈帧中使用。要从中访问这些全局变量f
,您可以使用堆栈检查:
import inspect
def f():
log = inspect.currentframe().f_back.f_globals['log']
log('Hi')
exec('f()', {'f': f, 'log': print})
如果您想f
使用提供的全局变量执行主体,而不仅仅是获得对全局变量的访问权限,则需要f
使用您自己的自定义全局变量制作副本:
import types
my_f = types.FunctionType(f.__code__,
{'log': print},
f.__name__,
f.__defaults__,
f.__closure__)
my_f()
函数类型构造函数有点文档化;它不在在线文档中,但记录在函数类型的文档字符串中:
function(code, globals[, name[, argdefs[, closure]]])
Create a function object from a code object and a dictionary.
The optional name string overrides the name from the code object.
The optional argdefs tuple specifies the default argument values.
The optional closure tuple supplies the bindings for free variables.
不确定我的解释是否完全正确。简而言之,该示例无法在 Python 3 中运行。
原因是两种情况的结合:[1] -exec
是 Python 3 中的函数,[2] - 您尝试执行的代码包含函数调用。
当您为函数提供globals
可选参数时,exec
它就是该函数的本地范围。所以下面的例子有效:
exec('log("Hi")', {'log': print})
但原来的没有。因为在原始示例中,您调用了函数f
。它有自己的本地范围。Python 做什么?它检查全局范围(程序的实际全局范围)和最内层范围(函数的本地范围f
)。两个范围都缺少log
,你得到NameError
.
您可以使用两个常规函数获得完全相同的行为(相同的错误):
def f():
log("Hi")
def f_():
log = print
f()
f_()