如何强制更新不同堆栈框架的 Python locals() 字典?

How can I force update the Python locals() dictionary of a different stack frame?

在 Python 2(不确定 3)中,locals 字典仅在您实际调用 locals() 时才会更新。所以例如

l=locals()
x=2
l['x']

失败,因为 l 中没有密钥 "x",但是

l=locals()
x=2
locals()
l['x']

returns 2.

我正在寻找一种强制更新本地字典的方法,但诀窍是我在不同的堆栈框架中。所以例如我想做

l=locals()
x=2
force_update()
l['x']

我需要编写 force_update() 函数。我知道从上述函数中我可以通过 inspect.currentframe().f_back 获取父框架,甚至通过 inspect.currentframe().f_back.f_locals 获取父(未更新的)局部变量,但我如何强制更新?

如果这看起来很复杂,我的主要目标是为 "{some} string".format(**dict(globals(),**locals())) 编写一个 shorthand 的函数,这样我就不必每次都输入它,而是可以 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_locals即可触发复制,因此使用inspect.currentframe().f_back.f_locals就足够了

参见frameobject.c实现中的frame_getlocals() function

static PyObject *
frame_getlocals(PyFrameObject *f, void *closure)
{
    PyFrame_FastToLocals(f);
    Py_INCREF(f->f_locals);
    return f->f_locals;
}

PyFrame_FastToLocals 是用于将数据从跟踪本地值的内部数组复制到字典的函数。 frame_getlocals用于实现frame.f_locals描述符(一个属性);见 frame_getsetlist definition.

上面使用的 PyFrame_FastToLocalsWithError 函数 正是 locals() 用来生成相同字典的函数(由 wrapping the PyEval_GetLocals function)。