如何在命名空间dict中执行函数?

时间:2014-02-12 00:43:06

标签: python python-3.x

说我有以下词典:

In [6]: scope
Out[6]: {'bar': <function bar>, 'foo': <function foo>}

foobar是:

def foo():
    return 5

def bar(x):
    return foo() + x

我想运行bar(1),但需要找到foo()。有没有办法在bar()命名空间中运行scope,以便找到foo()

我不确切知道scope bar中哪个函数需要,因此我需要在bar命名空间中运行scope的一般方法。我没有源代码,也无法修改任何函数来接受dict。

似乎函数具有__closure__属性,但它是不可变的。还有一个__globals__属性,但它只指向globals()。我已经看到更新locals()的一些答案,但我希望保持locals()不受影响。

我在eval中尝试了scope,但NameError获得了foo

In [12]: eval(scope['bar'](1), scope)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-12-f6305634f1da> in <module>()
----> 1 eval(scope['bar'](1), scope)

<string> in bar(x)

NameError: global name 'foo' is not defined

是否有一些我想念的简单方法?

2 个答案:

答案 0 :(得分:4)

一种方法是使用共享全局字典创建新函数:

from types import FunctionType

def scopify(**kwargs):
    scoped = dict()
    for name, value in kwargs.items():
        if isinstance(value, FunctionType):
            scoped[name] = FunctionType(value.__code__, scoped, name)
        else:
            scoped[name] = value
    return scoped

scope = scopify(
    foo = lambda: baz,
    bar = lambda x: foo() + x,
    baz = 5,
)

>>> scope['foo']
5
>>> scope['bar'](10)
15
>>> scope['baz'] = 100
>>> scope['bar'](10)
110

答案 1 :(得分:2)

使用eval()会有效,但尝试使用它的方式存在两个问题。首先,它的第一个参数 expression 应该是一个字符串。其次,由于您在此表达式中引用scope并将作为 globals 命名空间参数传递给eval(),因此您需要添加它本身。

这说明了我的意思:

def foo():
    return 5

def bar(x):
    return foo() + x

scope = {'scope': {'bar': bar, 'foo':foo}}  # define self-referential scope
expression = "scope['bar'](42)"  # explicit reference to `scope`
print('eval({!r}, scope) returns {}'.format(expression, eval(expression, scope)))

但是,在这种特定情况下,让eval()直接查找bar字典名称空间本身scope的值(而不是via {{}会更简单1}}):

scope['scope']['bar']