是否可以从解释器中运行的python代码写入sys._getframe()返回的python框架对象?

StackOverflow https://stackoverflow.com/questions/626835

适用于这问题,解释器中有一些脚手架来检查框架对象,可以通过 sys._getframe()检索。框架对象看起来是只读的,但我在文档中找不到任何明显说明这一点的东西。有人可以确认这些对象是可写的(以某种方式)还是只读的?

import sys

def foobar():
    xx='foo'
    ff = sys._getframe()
    ff.f_locals['xx'] = 'bar'
    print xx

if __name__ == '__main__':
    foobar()

这会在运行时输出' foo ',但下面的帖子演示了从交互式shell中的当前帧运行时变量是否可写。

有帮助吗?

解决方案

从CPython源代码, Objects / frameobject.c

static PyMemberDef frame_memberlist[] = {
    {"f_back",      T_OBJECT,       OFF(f_back),    RO},
    {"f_code",      T_OBJECT,       OFF(f_code),    RO},
    {"f_builtins",  T_OBJECT,       OFF(f_builtins),RO},
    {"f_globals",   T_OBJECT,       OFF(f_globals), RO},
    {"f_lasti",     T_INT,          OFF(f_lasti),   RO},
    {"f_exc_type",  T_OBJECT,       OFF(f_exc_type)},
    {"f_exc_value", T_OBJECT,       OFF(f_exc_value)},
    {"f_exc_traceback", T_OBJECT,   OFF(f_exc_traceback)},
    {NULL}    /* Sentinel */
};
...
static PyGetSetDef frame_getsetlist[] = {
    {"f_locals",    (getter)frame_getlocals, NULL, NULL},
    {"f_lineno",    (getter)frame_getlineno,
                    (setter)frame_setlineno, NULL},
    {"f_trace",     (getter)frame_gettrace, (setter)frame_settrace, NULL},
    {"f_restricted",(getter)frame_getrestricted,NULL, NULL},
    {0}
};

对于 PyMemberDef ,标志 RO READONLY 意味着它的属性是只读的。对于 PyGetSetDef ,如果它只有一个getter,那么它是只读的。这意味着除了 f_exc_type f_exc_value f_exc_traceback f_trace 之外的所有属性在创建后都是只读的。在数据模型下的文档中也提到了这一点。

属性引用的对象不一定是只读的。你可以这样做:

>>> f = sys._getframe()
>>> f.f_locals['foo'] = 3
>>> foo
3
>>>

虽然这在解释器中起作用,但它在函数内部失败。执行引擎为局部变量( f_fastlocals )使用一个单独的数组,在访问时将其合并到 f_locals 中,但反之则不然。

>>> def foo():
...   x = 3
...   f = sys._getframe()
...   print f.f_locals['x']
...   x = 4
...   print f.f_locals['x']
...   d = f.f_locals
...   x = 5
...   print d['x']
...   f.f_locals
...   print d['x']
...
>>> foo()
3
4
4
5
>>>

在全局框架中, f_local 引用 f_globals ,这使得这个技巧在解释器中起作用。修改 f_globals 有效,但会影响整个模块。

其他提示

NXC的f_locals ['foo']示例有效,因为代码在模块范围内。在这种情况下,f_locals是f_globals,f_globals都是可修改的,修改会反映在模块中。

在函数范围内,locals()和f_locals是可写的,但“[更改可能不会影响解释器使用的局部变量的值]。” 1 这是一个实施选择。在CPython中,有一个优化的局部变量字节码LOAD_FAST。在Python中,一旦定义了函数,(几乎总是)知道局部变量,CPython使用索引查找来获取变量值,而不是字典查找。

理论上,字典查找可以代理该表,但这是很多工作,但收效甚微。

“局部变量已知”的例外情况如果函数使用exec语句,并且不推荐使用“来自模块导入*”的情况。对于这些情况,生成的字节代码不同,速度较慢。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top