통역사 내에서 실행되는 Python 코드에서 Sys._getFrame ()에 의해 반환 된 Python 프레임 개체에 쓸 수 있습니까?
-
06-07-2019 - |
문제
apropos의 이 질문, 통역사 내에는 프레임 객체를 검사하기 위해 약간의 비계가 있습니다. sys._getframe()
. 프레임 객체는 읽는 것처럼 보이지만, 문서에서 명시 적으로 언급하는 명백한 것을 찾을 수는 없습니다. 누군가이 객체를 쓸 수 있는지 (어떤 방식으로) 읽을 수 있는지 확인할 수 있습니까?
import sys
def foobar():
xx='foo'
ff = sys._getframe()
ff.f_locals['xx'] = 'bar'
print xx
if __name__ == '__main__':
foobar()
이것은 인쇄한다 'foo
'실행할 때 아래 게시물은 대화식 쉘에서 현재 프레임에서 실행될 때 쓸 수있는 변수를 보여줍니다.
해결책
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는 수정 가능하고 수정은 모듈에 반영됩니다.
기능 범위 내부에서 Localals () 및 F_Locals는 쓰기가 가능하지만 [변경 사항은 통역사가 사용하는 로컬 변수의 값에 영향을 미치지 않을 수 있습니다]." 1 구현 선택입니다. Cpython에는 로컬 변수에 대한 최적화 된 바이트 코드가 있습니다. Load_fast. 파이썬에서 로컬 변수는 함수가 정의되면 (거의 항상) 알려져 있으며 Cpython은 사전 조회가 아닌 변수 값을 얻기 위해 색인 조회를 사용합니다.
이론적으로 사전 조회는 그 테이블을 프록시 할 수 있지만, 이는 작은 이득을 얻기위한 많은 작업입니다.
"로컬 변수"에 대한 예외는 함수가 exec 문을 사용하고 "Module Import *"의 더 이상 사용되지 않은 경우입니다. 생성 된 바이트 코드는 이러한 경우에 따라 다르고 느립니다.