【问题标题】:Is it possible to access exec-provided globals dictionary from within a function?是否可以从函数中访问 exec 提供的全局字典?
【发布时间】:2018-11-02 01:29:06
【问题描述】:

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

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

def f():
    log("Hi")

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

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

【问题讨论】:

  • 很遗憾,您没有提供有关该问题的任何上下文。那么,为什么不只使用exec('log = print; f()')?然后这个例子就起作用了。
  • 可能存在多种情况,其中替换函数的全局变量可能是有意义的。假设我对在提供新的(或重新定义现有的)全局函数或变量的环境中执行代码感兴趣。假设我希望这些定义适用于任何外部代码,例如通过导入拉入脚本。不过,总的来说,我最感兴趣的是对问题的答案完全符合所述 - “是否有可能以某种方式访问​​ exec 提供的全局变量?”

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


【解决方案1】:

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

您的 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.

【讨论】:

    【解决方案2】:

    不确定我的解释是否完全正确。 简而言之,该示例无法在 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_()
    

    【讨论】:

      猜你喜欢
      • 2021-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-13
      • 2019-05-28
      • 2013-05-18
      • 1970-01-01
      • 2016-09-28
      相关资源
      最近更新 更多