Python:如何在eval中访问eval的globals()

时间:2012-09-21 09:09:55

标签: python scope eval

标题似乎很愚蠢,但我不知道如何准确表达,抱歉。

我有一个程序需要评估一些用户代码(通过RestrictedPython以获得安全性)并且我想将一个函数放入eval的全局变量中,以便它可以在eval时打印出一些调试信息,例如(简化) :

class UserException(Exception):
    pass


def err(msg):
    # ? how to get the globals variable in eval ?
    A = globals().get('A', 'A not found')
    return UserException("%s and A's value is %r" % (msg, A))

g = {
    'err': err,
    'A': None,
    '__builtins__': {},
}

print eval('A or err("A not true")', g)

这将给出结果:

A not true and A's value is 'A not found'

在这里使用'globals()'insde'err'当然是错误的。但是如何才能在'err'中获得'g'中的值?

2 个答案:

答案 0 :(得分:1)

您可以将g作为默认参数传递:

def err(msg, g=g):
    A = g['A']
    return UserException("%s and A's value is %r" % (msg, A))

会给出结果:A not true and A's value is None

答案 1 :(得分:1)

在函数内部对globals()的任何引用都将始终为您提供定义函数时范围内的全局变量。你在这里看到的与将一个函数从一个模块导入另一个模块没有什么不同:导入的函数仍然引用模块的全局变量。

让函数使用g作为globals()的最简单方法是使用g作为全局变量来执行定义。如果你确实更改了函数的全局变量,那么不要忘记你还需要包含函数使用的任何其他全局变量;在这种情况下UserException

或者你可以让err()检查其调用者的堆栈帧并使用调用者的全局变量。这很麻烦,但如果是调试信息可能是你可以接受的。

>>> def err(msg):
    # ? how to get the globals variable in eval ?
    A = sys._getframe(1).f_globals.get('A', 'A not found')
    return UserException("%s and A's value is %r" % (msg, A))

>>> import sys
>>> g = {
    'err': err,
    'A': None,
    '__builtins__': {},
}
>>> print eval('A or err("A not true")', g, g)
A not true and A's value is None
>>>