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

时间:2018-11-02 01:29:06

标签: python python-3.x python-exec

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

换句话说,有没有办法使以下示例正常工作?

def f():
    log("Hi")

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

通常,可以用功能__globals__代替吗?

2 个答案:

答案 0 :(得分:1)

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

您的exec调用在提供的全局变量中执行语句f()。它不会在提供的全局变量中执行f body 。提供的全局变量在错误的堆栈框架中使用。要从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.

答案 1 :(得分: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_()