说我有以下词典:
In [6]: scope
Out[6]: {'bar': <function bar>, 'foo': <function foo>}
而foo
和bar
是:
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
是否有一些我想念的简单方法?
答案 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']