2009-07-17 3 views
5

파이썬에서 함수의 로컬 네임 스페이스를 수정하려면 어떻게해야합니까? locals()는 함수 내부에서 호출 될 때 함수의 로컬 네임 스페이스를 반환한다는 것을 알고 있지만 이와 같은 작업을 수행하려고합니다 (g가 f에 액세스 할 수없는 곳에서이 작업을 수행해야하는 이유가 있지만이를 제공하는 것이 더 빠릅니다. 문제를 설명하기 위해 사소한, 어리석은 예제) :파이썬에서 로컬 네임 스페이스를 수정하는 방법

+0

이 이상한 기술을 사용하여 당신의 궁극적 인 목표는 무엇을 작동하는 것 같다? f()보다 먼저 g()를 정의 할 수없는 이유는 무엇입니까? –

+0

이전에 (테스트/조롱을 위해) 런타임에 함수의 네임 스페이스를 엉망으로 만들려고했지만 실패했습니다 ... 그냥 참고하십시오. –

+0

도대체'add_to_locals'는 무엇입니까? 그것은 나에게 존재하지 않는 것 같습니다. 'AttributeError : 'function'객체에 'add_to_locals'속성이 없습니다. –

답변

3

함수가 호출되지 않았으므로 아직 "로컬"스택 프레임이 없습니다. 가장 간단한 해결책은 글로벌 컨텍스트를 사용하는 것입니다

handler = None 
def f(): 
    handler() 

def g(): pass 

handler = g 

아니면 함수 객체에 g을 설정할 수 있습니다 :

f.g = g 

하지만 난 당신이 내에서 함수 객체를 얻을 수있는 방법 확실하지 않다 함수 자체. 방법 이었으면 self을 사용합니다.

+0

당신이 * 정말 * 함수 내에서 함수 객체를 사용하고자하는 경우, 당신은 검사 사용할 수 있습니다 수입 수입 pprint DEF FN() 검사 : 프레임 = inspect.currentframe() 인쇄 frame.f_globals를 [프레임 .fucode.co_name] .g fn.g = 'hello' fn() – Ivo

+0

클래스 함수, 중첩 된 함수/클로저 및 람다에 대해 오류가 발생했으며 꾸며진 것이 있습니다. 데코레이터의 래핑 함수가 반환됩니다. 실제 함수. –

+0

'f'가 클래스/인스턴스 메소드라면? –

1

실행되지 않는 함수에는 지역 변수가 없습니다. 함수를 실행할 때 로컬 컨텍스트가 작성되고 종료 될 때 파손되므로 함수 외부에서 수정할 "로컬 네임 스페이스"가 없습니다.

당신은하지만, 같은 것을 할 수 있습니다

def f(): 
    g = [1] 
    def func(): 
     print g[0] 
    return func, g 

f, val = f() 
f() 
val[0] = 2 
f() 

이것은 참조를 시뮬레이션하기 위해 배열을 사용합니다.

+2

이 사이트는 -1 투표에 대한 설명이 필요하므로 사람들은 이유없이 정답을 익명으로 투표 할 수 없습니다. –

2

완전히 다른 점에서 문제를 해결할 수 있다고 생각합니다.
함수는 사전과 함께 객체입니다. 따라서 F에 g을 추가하고 사용을 할 수 있습니다

def g(): 
    print "g" 

def f(): 
    f.g() 

f.g = g 
+0

매우 우아한 솔루션입니다. +1 – Josip

+0

이것은 글로벌 기능에서만 작동합니다. f 안에서 안전하게 f에 액세스 할 수있는 방법이 없습니다. –

+0

이것을 확장 할 수 있습니까? 파이썬 함수는 객체이며 지역적이거나 전역적일 경우 차이가 없습니다. - 당신이 _methods_를 의미하지 않는 한, 그것은 완전히 다른 이야기이며 OP가 요구하지 않은 것입니다. –

3

왜 그냥 f()에 인수를 추가하고 g()에 대한 참조를 전달하지?

def g(): 
    pass 

def f(func): 
    func() 

f(g) 
2

함수 f는 사용자가 아니고 다른 모듈에 의해 정의 되었기 때문에이 작업을 수행한다고 가정합니다. 그래서 f()가 어떻게 작동하는지 바꾸고 싶습니다. 특히 g가 호출 될 때 호출되는 것을 변경하려고합니다.

그래서 나는이 제안 것이다 :이 모듈 thirdpartypackage에 대한 글로벌 g 변경됩니다

import thirdpartypackage 

def mynewg(): 
    pass 

thirdpartypackage.g = mynewg 

. 따라서 thirdpartypackage.f()가 호출되면 g() 대신 mynewg()가 호출됩니다.

이렇게해도 해결되지 않으면 실제로 g()가 f()를 사용하여 가져 오거나 실제로 존재하지 않을 수 있습니다. 그러면 해결책은 다음과 같습니다.

import thirdpartypackage 

def mynewg(): 
    pass 

deg mynewf(): 
    mynewg() 

thirdpartypackage.f = mynewf 

즉 f()를 원하는대로 수정 된 버전으로 완전히 대체합니다.

8

몇 가지 옵션이 있습니다. 첫째, 예제에서 g는 실제로 함수에 대한 로컬이 아니며 (즉, 그 안에 할당되지 않았습니다.) 전역 변수입니다 (즉, 로컬 변수에 할당되지 않았습니다). 이는 함수가 정의 된 모듈에서 찾아 볼 것임을 의미합니다. 함수가 실행될 때 이전에 할당되지 않았으므로 외부에서 지역 변수를 변경할 방법이 없습니다 (바이트 코드 패치 부족).

하나의 옵션은 단순히 함수를 모듈의 네임 스페이스에 삽입하는 것입니다. 이것은 작동 할 것이지만, 하나의 함수가 아니라 변수에 접근하는 해당 모듈의 모든 함수에 영향을줍니다.

하나의 함수에만 영향을 주려면 func_globals를 다른 위치로 지정해야합니다. 불행하게도,이 속성은 읽기 전용입니다,하지만 당신은 같은 몸 기능을 다시 만들어 당신이 원하는 것을 할 수 있지만 다른 글로벌 네임 스페이스 : 그것은 모양을 제외하고

import new 
f = new.function(f.func_code, {'g': my_g_function}, f.func_name, f.func_defaults, f.func_closure) 

f는 지금, indentical 될 것입니다 제공된 사전에있는 전역에 대해 이것은 전체 글로벌 네임 스페이스를 리바 인 딩합니다. f 이있는 변수가있는 경우을 찾아보십시오. 또한 해당 변수를 제공했는지 확인하십시오. 이것은 상당히 해킹 된 것으로 cpython 이외의 다른 python 버전에서는 작동하지 않을 수도 있습니다.

+1

이것이 "좋은"코드인지는 모르겠지만 정확히 내가 원했던 것입니다. 하나의 코드베이스를 다른 코드베이스로 변환하고 다른 언어의 언어 구문을 시뮬레이션 할 수 있기를 원했습니다. 다른 언어는 코드를 패키지화하고 해당 코드를 네임 스페이스에 추가하거나 제거 할 수 있습니다. 다른 기능을 무시할 때 유용합니다. 그래서 네임 스페이스를 유행처럼 스택에서 조작합니다. 이것은 제가 효율적으로 그렇게 할 수있는 가장 가까운 것입니다. 감사합니다 – Demolishun

+0

이'new' 라이브러리는 무엇입니까? –

+0

'exec' 또는'locals(). update (d)'에 무슨 문제가 있습니까? –

0

def add_to_locals(l): 
    l['newlocal'] = 1 

add_to_locals(locals()) 
assert newlocal 
+0

함수 내에서 작동하지 않습니다. 네임 스페이스에 값을 추가하지 않습니다. – Demolishun

관련 문제