0

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

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

def f():
    log("Hi")

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

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

4

2 回答 2

1

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

您的 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.
于 2018-11-04T16:34:51.670 回答
0

不确定我的解释是否完全正确。简而言之,该示例无法在 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_()
于 2018-11-04T15:52:24.777 回答