来自 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
,如果它只有一个吸气剂,它是只读的。这意味着除了 、 和 之外的所有属性f_exc_type
在创建f_exc_value
后都是只读的。这也在文档中的Data model下提到。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
有效,但会影响整个模块。