我有一个callback
可调用,它是在exec()
内计算的。
我在此_globals
中使用了_locals
和exec()
。 variable_from_context
中有一个键为_locals
的值。
但是当我尝试调用callback()
时,它在当前上下文中执行,而不是在其原始上下文中执行。找不到variable_from_context
。
exec()
只接受str
或代码对象。我发现这种方式可以访问callback
的代码对象,并尝试调用它:
exec(callback.__code__, scenario._globals, scenario._locals)
但是,我得到NameError: name 'variable_from_context' is not defined
。
使用给定的callback
和globals
致电locals
的正确方法是什么?
代码示例:
der_callback = None
def save_callback(cb):
der_callback = cb
_locals = {}
_globals = {'save_callback': save_callback}
text = r'''
zoo = ['we']
def foo():
print(zoo[0])
save_callback(foo)
'''
exec(text, _globals, _locals)
print(_locals)
# One can also try this:
# exec(_locals['foo'].__code__, _globals, _locals)
# EDIT: Now, why doesn't _locals get used when invoking a function?
# This works:
# exec('print(zoo[0])', _globals, _locals)
# EDIT continues: This doesn't:
# exec('foo()', _globals, _locals)
_locals['foo']()
输出:
Traceback (most recent call last):
{'zoo': ['we'], 'foo': <function foo at 0x1020b2d90>}
File "/Users/me/pyzoo/callback_from_eval.py", line 22, in <module>
exec(_locals['foo'].__code__, _globals, _locals)
File "<string>", line 5, in foo
NameError: name 'zoo' is not defined
答案 0 :(得分:2)
首先,任何上下文都有其全局变量和本地变量。在模块级别,它们是等效的(相同的字典)。在其他情况下,它们通常不同。除非您将某些内容声明为global
,否则任何赋值都会修改上下文本地,但不会修改全局变量。
然后,任何函数都有自己的本地。因此,在输入foo
时,_globals
被视为全局,但_locals
不被视为本地人。因此,zoo
不可见。直接修复是在分配到块中之前说global zoo
。
另外,您在save_callback
中暴露了同样的问题:赋值给der_callback
并不会改变全局变量,而是一个在退出后立即丢失的局部变量。要修复,请在函数内声明der_callback
为全局。
UPD:如果您需要chunk-top locals,您可以尝试以下技巧之一:
T1。在chunk global level上,为locals()指定一个名称,并在foo()中重用它:
globals()['xl'] = locals()
zoo = ['we']
def foo():
print(xl['zoo'][0])
T2。使用调用堆栈帧查找:
在大块之外:
def save_callback(cb):
global der_callback
der_callback = lambda: cb(sys._getframe(1).f_locals)
在foo定义中:
def foo(xl):
print(xl['zoo'][0])
答案 1 :(得分:1)
正如Netch所说,你的
def save_callback(cb):
der_callback = cb
不分配给全局der_callback
。它将cb
对象绑定到本地名称der_callback
,当然,当函数退出时,该绑定将丢失。要从函数内部分配全局对象,必须使用global
指令。
也许这段代码可以帮助您了解正在发生的事情。
der_callback = None
def save_callback(cb):
global der_callback
der_callback = cb
def show_dict(d, name):
print(name)
for k in sorted(d.keys()):
if not k[0] == '_':
print('{!r}: {!r}'.format(k, d[k]))
print()
text = r'''
zoo = ['we']
def foo():
print(zoo[0])
save_callback(foo)
show_dict(globals(), 'text GLOBALS')
'''
_globals = {
'save_callback': save_callback,
'show_dict': show_dict,
}
exec(text, _globals)
zoo = ['hello']
show_dict(globals(), 'module GLOBALS')
print(der_callback)
der_callback()
<强>输出强>
text GLOBALS
'foo': <function foo at 0xb71d5cd4>
'save_callback': <function save_callback at 0xb725553c>
'show_dict': <function show_dict at 0xb71d5c8c>
'zoo': ['we']
module GLOBALS
'der_callback': <function foo at 0xb71d5cd4>
'save_callback': <function save_callback at 0xb725553c>
'show_dict': <function show_dict at 0xb71d5c8c>
'text': "\nzoo = ['we']\n\ndef foo():\n print(zoo[0])\n\nsave_callback(foo)\n\nshow_dict(globals(), 'text GLOBALS')\n"
'zoo': ['hello']
<function foo at 0xb71d5cd4>
we
在这两种情况下,locals()
与globals()
相同,您可以将locals()
传递给show_dict
来查看。
以下是您的代码的略微修改版本,我认为它可以满足您的需求。
der_callback = None
def save_callback(cb):
der_callback = cb
_globals = {'save_callback': save_callback}
text = r'''
zoo = ['we']
def foo():
print(zoo[0])
save_callback(foo)
'''
exec(text, _globals)
_globals['foo']()
<强>输出强>
we
exec
调用相当于
exec(text, _globals, None)