如何强制更新不同堆栈框架的Python locals()字典?
在Python 2中(不确定是否为3),只有在实际调用locals()时,才会更新locals字典。例如 失败,因为如何强制更新不同堆栈框架的Python locals()字典?,python,python-internals,inspect,stack-frame,locals,Python,Python Internals,Inspect,Stack Frame,Locals,在Python 2中(不确定是否为3),只有在实际调用locals()时,才会更新locals字典。例如 失败,因为l中没有键“x”,但是 l=locals() x=2 locals() l['x'] 返回2 我正在寻找一种强制更新本地词典的方法,但诀窍是我处于不同的堆栈框架中。所以,例如,我希望 l=locals() x=2 force_update() l['x'] 我需要编写force\u update()函数。我知道,通过上述函数,我可以通过inspect.currentframe(
l
中没有键“x”,但是
l=locals()
x=2
locals()
l['x']
返回2
我正在寻找一种强制更新本地词典的方法,但诀窍是我处于不同的堆栈框架中。所以,例如,我希望
l=locals()
x=2
force_update()
l['x']
我需要编写force\u update()
函数。我知道,通过上述函数,我可以通过inspect.currentframe().f_back
获取父帧,甚至可以通过inspect.currentframe().f_back.f_locals
获取父(未更新)局部变量,但我如何强制更新呢
如果这看起来很复杂,我的主要目标是编写一个函数,它是“{some}string.format(**dict(globals(),**locals())
的缩写,因此我不必每次都键入它,而是可以执行fmt({some}string”)
。这样我就遇到了上面的问题
编辑:下面是Martjin的答案,下面就是我想要的解决方案。我们可以仔细研究如何获得被调用方的堆栈帧,这里我通过partial
实现
from functools import partial
from inspect import currentframe
fmt = partial(lambda s,f: s.format(**dict(globals(),**f.f_locals)),f=currentframe())
x=2
print fmt("{x}") #prints "2"
只需访问帧对象上的f_局部变量
即可触发复制,因此使用inspect.currentframe().f_back.f_局部变量
就足够了
请参见frameobject.c
实现中的:
静态PyObject*
frame_getlocals(PyFrameObject*f,void*closure)
{
PyFrame_FastToLocals(f);
Py_增量(f->f_局部变量);
返回f->f_局部变量;
}
PyFrame\u FastToLocals
是用于将数据从内部数组跟踪局部值复制到字典的函数frame\u getlocals
用于实现frame.f\u locals
描述符(一个属性);看
上面使用的
PyFrame\u FastToLocalsWithError
函数正是locals()
用来生成同一个字典的函数。在编辑器中,您可以定义一个快捷方式、代码段或任何编辑器调用的函数,以扩展到。格式(**dict(globals(),**locals())
。很多编辑器都支持这样的功能。为什么在代码中多次使用“{some}string.format(**dict(globals(),**locals())
?您的格式字符串真的需要访问本地和全局名称空间中的每个变量吗?如果您可以获得父帧(请参见sys.\u getframe(1)
),那么为什么需要globals()
和locals()
?啊哈!谢谢我设法找到了currentframe().f_locals
,但没有意识到它确实会强制我正在寻找的更新。是的-请注意,不会发生相反的情况-无法通过更改局部变量中的值来更新快速变量。@CharlieParker:我在回答中链接到了Python 3源代码;是的,它在Python3中工作。@MartijnPieters等待您是否真的能够更新局部变量并使其工作?我一直在找这样的东西,一点运气都没有。为什么你的方法有效,而其他方法却失败了?@CharlieParker:Python在函数中大量优化了局部名称空间。
from functools import partial
from inspect import currentframe
fmt = partial(lambda s,f: s.format(**dict(globals(),**f.f_locals)),f=currentframe())
x=2
print fmt("{x}") #prints "2"