2013-07-11 2 views
2

나는이 기능을 기본적으로 지원하지 않는다는 것을 알고있다. 내가 시도하고있는 것은 실용적인 애플리케이션이 거의없는 해킹 된 해결책이다. 지루함과 호기심의 결과로 정신적 자위에서 완전한 연습. 그건 내가 다음 할 노력하고있어, 말했다 : 다음 파이썬 코드에 근거하여Python에서 런타임시 로컬 변수의 이름을 얻는 것

,

with BuildFile('mybuild.build') as buildfile: 
    objdir = 'obj' 

나는 내용으로 mybuild.build 파일을 생성하고 싶습니다 :

objdir = obj 

이상적으로, 나는 생성 시점에서 변수 이름을 연관시키고 싶습니다. 따라서 objdir = 'obj' 다음에 중단 점을 설정하면 다음을 수행하고 싶습니다.

>>> print repr(objdir) 
'objdir = obj' 

그러나 구문에서 유추 된 형식을 재정의 할 수있는 방법이 없으므로 기본 제공 기능을 사용하여 이러한 기능을 구현할 수는 없습니다. 함께 해결 방법을 해킹 할 수도 있습니다. PyTypeObject 구조체의 tp_new 또는 tp_dict 필드에 원숭이 패치를 적용한 다음 (다시 말하면 해당 재정의를 되돌리기 위해) ctypes 메서드를 사용합니다. 그러나 간단하게하기 위해 내가 BuildFile.__exit__ 메서드에 도달 할 때까지 변수 이름을 연결하지 않습니다. 내가 궁금하고있어

않습니다 :

가 실행을 중지 로컬 변수가 선언 된 프레임으로 추적하고, 변수와 관련된 로컬 이름을 얻기를위한 내장 파이썬 기능이 있습니까?

+0

"실행 중지"란 무엇을 의미합니까? 디버거는 스크립트의 실행을 멈출 수 있지만 스크립트가 실행을 중지하면 더 이상 실행되지 않으므로 아무 것도 할 수 없습니다. – abarnert

+0

예, "중지 실행"은 단어의 매우 열악한 (그리고 부정확 한) 선택이었습니다. 제가 말하고자했던 것은 그 위치에 상대적으로 보이는 곳을 정하기위한 목적으로 "현재의 경계표"였습니다. –

+0

OK, 네, 그게'sys._getframe()'이하는 일입니다. 프레임 객체를 나중에 저장하고 프레임 외부에서 사용할 수도 있습니다 (보통 나중에 GC를 정리할 순환 참조를 많이 만들지 만). 예를 들어'[in range (1)] [0] .f_code'에 대한'[sys._getframe()]은 CPython listcomps 안의 숨겨진 함수를 얻을 수있게 해주고, 더 깨끗한 방법으로는 생각할 수 없습니다. – abarnert

답변

1

파이썬에는 프레임 추적을위한 휴대용 방법이 없지만 CPython 구현은 다음을 수행합니다. sys._getframe은 프레임 객체를 반환합니다.

프레임 개체로 무엇을 할 수 있습니까? 프레임에 표시되는 locals()globals()과 프레임에서 실행되는 코드 객체 (로컬 이름, 언 바운드 이름 및 셀 포함)를 포함하는 모든 재미있는 것들에 대해서는 inspect 문서의 편리한 차트를 참조하십시오. 폐쇄.

그러나 다른 사람들이 지적했듯이이 프레임을 실제로 필요로하지는 않습니다. 당신이 필요로하는 것은 현지인 뿐이고 컨텍스트 관리자에게 명시 적으로 전달하는 것이 훨씬 간단합니다.당신이 정말로 이렇게 할 경우


: 실행하면

import contextlib 
import sys 

@contextlib.contextmanager 
def dumping(): 
    f = sys._getframe(2) 
    fl = f.f_locals.copy() 
    try: 
     yield None 
    finally: 
     for name, value in f.f_locals.items(): 
      if name not in fl: 
       print('{} = {}'.format(name, value)) 

bar = 0 
def foo(): 
    global bar 
    bar = 3 
    baz = 4 
    qux = 5 
    with dumping(): 
     spam = 'eggs' 
     eggs = 3 
     bar = 4 
     baz = 5 

foo() 

이 인쇄한다 : 즉

eggs = 3 
spam = eggs 

만 새 변수의 이름과 값을하는 with 블록 내에서 선언되었습니다. 내 생각에, 당신이 원했던 것입니까? 둘 다 새로운 리바운드 지역 주민을 원하는 경우에


, 당신은 아마 이런 식으로 뭔가 저장할 것 : 당신은 또한 nonlocals 및 전역을 바인딩 할 수 물론

fl = {(name, id(value)) for name, value in f.f_locals.items()} 

을, 그래서 당신은 그것에 대해 걱정하는 경우 , 전역을 숨기거나 (모듈 레벨 코드의 경우 locals is globals을 확인하십시오) 닫히거나 닫습니다.


당신이 CPython의 2를 사용하는 경우 (그 이유는 무엇입니까? 실제 프로젝트를 위해 가끔 의미가 있지만, 아직 내부는 재미를 위해 작동하는 방법입니까?하고, 어떤 사람들에 ...), 같은 코드가 작동합니다. 약간 다른 속성 이름이있을 수 있지만 프레임과 코드의 dir을 버리면 추측 할 수 있습니다. 그리고 분명히 2.x print 구문을 원합니다.

PyPy에서도 2.0b 이상 작동합니다.


하는 당신은 내가 _getframe(2)를 사용하여 어떻게 알았는지 궁금해하는 경우 ... 나는하지 않았다. 나는 그것이 1 또는 2 프레임 위로, 아마도 3 일 것이라고 확신했다. 그러나 어느 것이 든? 그래서 방금 이렇게했습니다.

@contextlib.contextmanager 
def dumping(): 
    for i in range(4): 
     f = sys._getframe(i) 
     print(f.f_code.co_filename, f.f_code.co_firstlineno, f.f_lineno) 

0은 물론 dumping입니다. 1은 contextlib.contextmanager의 래퍼 함수입니다. 2는 호출 프레임입니다. 3은 모듈 최상위 레벨입니다. 일단 당신이 그것에 대해 생각하면 명백합니다. 그러나 그 대답을 알기 전까지는 분명하지 않았습니다. :)

+0

자세한 답변을 보내 주셔서 감사합니다. 다른 의견에서 언급했듯이 프레임 경로를 이동하려는 생각은 대부분 yield 문 및 contexlib 기능에 대한 오해에 기반을 둡니다. 이를 기반으로 아마 그 길을가는 것은 아니지만,이 정보는 확실히 미래를위한 좋은 참고 자료가 될 것입니다. 파이썬 3을 2 이상 사용하는 것에 관해서는, 파이썬은 현재 나의 "똥과 낄낄 거림"아이디어 중 하나를 구현하고자 할 때 선택 언어입니다. 현재 CPython 2 용 C API는 내 용도로 사용하기에 조금 더 편리하므로 아직 점프 할 필요가 없다고 생각합니다. 다시 한번 감사드립니다. –

+0

@juntalis : 그래, 여기 프레임을 실제로 사용하는 유일한 방법은 부모님의 지역 주민들을 방문하는 것뿐입니다. 더 쉬운 방법이 있습니다.한편, 차이점이있을 때 Python 3은 일반적으로이 두 가지 중에서 더 합리적이고 흥미 롭다. 분명한 이유가있다. 그러나 PyPy는 탐구하기에 꽤 흥미 롭다. 3.x는 아직하지 않기 때문에 여전히 나 자신을 찾는다. 때로는 2.x 배짱으로 재미도 있습니다 ... – abarnert

2

사실이 같은 비슷한 트릭을 수행 할 수 있습니다

>>> from contextlib import contextmanager 
>>> @contextmanager 
def override_new_vars(locs): 
    old_locals = locs.copy() 
    yield 
    new_locals_names = set(locs) - set(old_locals) 
    for name in new_locals_names: 
     locs[name] = '%s = %r' % (name, locs[name]) 


>>> with override_new_vars(locals()): 
    c = 10 


>>> c 
'c = 10' 

를 귀하의 경우는 같을 것이다

with BuildFile('mybuild.build') as buildfile, override_new_vars(locals()): 
    objdir = 'obj' 

당신이하고 싶었던 무엇인가요?

0

나는 당신이 시도 할 수 있다고 생각 :

from copy import copy 
objdir = 'obj' 

def get_variable_name(variable): 

    if variable: 
     variables = copy(locals()) 
     for i in variables: 
      if variables.get(i) == variable: 
       res = i + '=' + variables.get(i) 
       return res 

사용이 트릭을 할해야한다, 나는 시험이 코드를 자신이있다.

관련 문제