是否可以从函数内访问 exec 提供的全局字典?

Is it possible to access exec-provided globals dictionary from within a function?

如果函数是在 exec 代码之外定义的(因此已经绑定到不同的 __globals__),是否可以从函数内部访问 exec 提供的全局字典?

换句话说,有没有办法让下面的例子起作用?

def f():
    log("Hi")

exec('f()', {'f': f, 'log': print})

一般来说,是否可以替换函数的__globals__

不确定我的解释是否完全正确。 简而言之,这个例子不能在Python 3.

中运行

原因是两种情况的组合:[1] - exec 是 Python 中的一个函数 3、[2] - 您尝试执行的代码包含函数调用。

当您向函数 exec 提供 globals 可选参数时,它是该函数的局部范围。所以下面的例子有效:

exec('log("Hi")', {'log': print})

但是原来的没有。因为在原始示例中,您调用了函数 f。它有自己的本地范围。 Python 做什么?它检查全局范围(程序的实际全局范围)和最内层范围(函数的局部范围 f)。两个范围都缺少 log,你得到 NameError.

您可以使用两个常规函数获得完全相同的行为(相同的错误):

def f():
    log("Hi")


def f_():
    log = print
    f()

f_()

这是一件很奇怪的事情,但它是可行的。

您的 exec 调用在提供的全局变量中执行语句 f()。它不会在提供的全局变量中执行 fbody。在错误的堆栈框架中使用了提供的全局变量。要从 f 访问这些全局变量,您可以使用 stack inspection:

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.