2012-01-20 2 views
0

저는 foo 모듈의 동작을 지시하는 몇 가지 모듈 수준 변수가 포함 된 foo 모듈을 사용하고 있습니다. 이러한 변수 중 하나는 SANITIZE입니다.모듈 변수를 원본 모듈에서 변경하지 않는 한 모듈에서 변경하십시오.

나는, foo.parse() 및 살균 = 내가 원하는 진정한

유일한 차이점은 foo는이 살균 = 거짓과에서는 foo2가있다 foo2.parse(), 두 가지 방법으로 foo에 사용할 수 있도록하려면 내 코드를 복사하여 복사 할 필요없이이 작업을 수행 할 수 있습니다. 예 :

#foo module 
SANITIZE='foo' 
def parse(): 
    print SANITIZE 

#foo2 module 
import foo 
foo.SANITIZE='foo2' 


#test script 
import foo 
import foo2 
foo2.foo.parse() #i want this to print 'foo2' 
foo.parse() #i want this to print 'foo' 

그러나 위의 예에서는 'foo2'를 두 번 인쇄합니다. 이 문제를 해결할 수있는 방법이 있습니까?

감사합니다.

+0

이 코드는 의미, foo.parse가되지 않습니다()는 어떤 경우에도 'foo'를 출력 할 것이고, 어떤 식 으로든 SANITIZE에 의존하지 않는 상수이다. – yurib

+0

유 리브에 대해 미안 해요. – djs22

+0

당신은 언제든지 delf와 foo.py를 다시로드 할 수 있습니다. –

답변

3

를, 솔루션보다 모듈 수준의 변수에 의존하는 것이 아니라 다른 방법으로 객체의 상태를 유지하는 것입니다. 파이썬 모듈은 "싱글 톤 (singletons)"입니다. 즉, 모듈에 의해 일단 임포트되면, 인터프리터 와이드 버전이 하나만 존재합니다. 예를 들어, 원하는 동작은 클래스를 사용하면 무료로 얻을 수 있습니다 상속 - 하위 클래스는 일부를 사용자 정의 할 수 있지만 모든 클래스를 다시 작성할 필요는 없습니다. 당신이 많은 클래스 내부에 "foo는"코드를 캡슐화 같은 경우

그래서 - 당신도 인스턴스를 필요로하는 클래스를 작성해야하지 않을 수 있습니다, 당신은 기능을 얻을 당신은 이미 원하는 :

#foo module: 

class Foo(object): 
    sanitize = "value 1" 
    @classmethod 
    def parse(cls): 
     print cls.sanitize 

#foo2 
from foo import Foo 
class Foo2(Foo): 
    sanitize = "value 2" 

# code: 
from foo import Foo 
from foo2 import Foo2 

Foo.parse() 
Foo2.parse() 

의 물론, 파이썬이 허용하는 내성과 메타 프로그래밍의 치어 리더 양과 함께라면, 이 원하는대로 할 수 있습니다.하지만 문제가 복잡 할 수 있습니다. 모듈 변수는 C 코드에서 전역 변수와 동일한 단점을 가지고 있습니다.

foo2를 통해 액세스 할 때 "foo"를 작성하여 변수를 즉시 변경하고 "foo"의 함수를 호출 한 다음 exit시 previosu 값을 복원하는 것이 한 가지 방법입니다. 모듈 "foo2"의 "foo"에 대한 속성 액세스에서 임의의 코드가 트리거되도록하려면 "foo"가 "속성"속성이있는 객체를 참조해야합니다. -

이렇게 작성한 EXA 예제는 에서는 foo2 더 또는 덜 작성된 경우, BTW하는 concurency 안전하지 않은 방법으로 매우 안전하지 않은 방법을 실행

import foo as _foo 

SANITIZE = "value2" 

class _FooWrapper(object): 
    def __getattribute__(self, attr): 
     self.change_vars() 
     original_function = getattr(_foo, attr) 
     if callable(original): 
      def wrapper(func): 
       def new_func(*args, **kw): 
        res = func(*args, **kw) 
        self.restore_vars() 
        return res 
       return new_func 
      return wrapper(original) 
     return original 

    def change_vars(self): 
     self.original_sanitize = _foo.SANITIZE 
     _foo.SANITIZE = SANITIZE 
    def restore_vars(self): 
     __foo.SANITIZE = self.original_sanitize 

foo = _FooWrapper() 

이 액세스 한 모듈에서는 foo2에 "foo는"객체를 생성은, 어떤에서 속성을 요청 검색 대신 원래 "foo"모듈. 그래서 "foo2.foo.parse"는 "foo"구문 분석 함수를 얻을 것이지만 -이 접근법에서 "hackiness"의 양을 인식합니다. - 내부에있는 "foo"모듈의 원래 값을 복원 할 수 있습니다. 파이썬 인터프리터는 함수가 foo2에서 가져온 후, 함수가 리턴했을 때 값 자체를 복원합니다. 이렇게하는 유일한 방법은 반환 할 때 추가 코드를 실행하도록 함수를 수정하는 것입니다. 위의 코드로 즉석에서 꾸며집니다.

이 예제는 가능한 경우 모듈 수준 구성을 사용하는 것이이 경우에는 사용할 수 없다는 것을 분명히합니다.

편집 O.P. 댓글 :

감사 jsbueno, 불행하게도이 내 코드가 아닙니다 내가 에 모듈 수준 변수를 의존해야합니다. 래퍼 클래스 방법은 재미 있지만 말했듯이, 매우 해키 내가 두려워 이

응답에서

것과 내 경우에하지 않을거야 믿을 수 없을 정도로 비 스레드 안전 :

모듈은 "싱글 톤"이므로 모듈의 변수를 변경하면 에 어떤 점이든 스레드가 안전하지 않게됩니다. 내가 생각할 수있는 다른 방법은 을 가져올 때 클래스, 속성 및 다른 인스턴스의 인스턴스를 실제로 다시 만드는 "복사기"모듈을 만드는 것입니다. 모든 함수 전역 변수를 리 바인드합니다 (메소드는 으로 여전히 처리됩니다). 그것은 "unfeasable"로 들리 겠지만이 설명을 읽고이 수준의 기능)

- 그러나 그것은 쉽게보다 수행 설명 - 다음은 위의 않습니다 내 "에서는 foo2"모듈을 다음을 :

from types import ModuleType, FunctionType 

import foo as _foo 

SANITIZE = "value 2" 

def rebuild_function(func, glob): 
    """Rebinds the globals in the given functions to globals in 
    this module by default""" 
    new_func = FunctionType(func.func_code, 
          glob, 
          func.func_name, 
          func.func_defaults, 
          func.func_closure) 
    return new_func 

def rebuild_class(cls, glob): 
    metatype = type(cls) 
    dct = cls.__dict__.copy() 
    for key, value in dct.items(): 
     if isinstance(value, FunctionType): 
      dct[key] = rebuild_function(value, glob) 
    return metatype(cls.__name__, cls.__bases__, dct) 

def rebuild_module(mod,glob): 
    new_module = ModuleType(mod.__name__) 
    for key, value in mod.__dict__.items(): 
     if isinstance(value, FunctionType): 
      value = rebuild_function(value, glob) 
     elif isinstance(value, type): 
      value = rebuild_class(value, glob) 
     setattr(new_module, key, value) 
    return new_module 

foo = rebuild_module(_foo, globals()) 

__all__ = ["foo", "SANITIZE"] 

이 코드는 정확하게 수행한다. 필자가 설명한 바에 따르면, 원래 모듈에있는 모든 함수 객체를 다시 만들고 각 함수에 대한 전역 명령을 재구성합니다. 동시성에 안전합니다. 클론 된 모듈이 네이티브 코드 클래스 나 함수를 가리키는 경우 ("FunctionType"이 아닌) 몇 가지 경우가 있습니다. 다중 클래스 상속, 메타 클래스를 많이 사용하는 경우 - 작업을하거나하지 않습니다.

나는 간단한 클래스를 테스트하고 그것을 잘 작동 :

#module "foo" 
SANITIZE='foo' 
def parse(): 
    print SANITIZE 

class Parser(object): 
    def __init__(self): 
     print SANITIZE * 2 

그리고

#test script 
import foo 
import foo2 
foo2.foo.parse() #i want this to print 'foo2' 
foo2.foo.Parser() 
foo.parse() #i want this to print 'foo' 
foo.Parser() 

을 출력 :

[[email protected] tmp16]$ python test_foo.py 
foofoo 
value 2 
value 2value 2 
foo 
foofoo 
[[email protected] tmp16]$ 
+0

감사합니다. jsbueno, 불행히도 이것은 내 코드가 아니며 모듈 수준 변수에 의존해야합니다. 래퍼 클래스 메서드는 재미 있지만 당신이 말했듯이 매우 위험하고 믿을 수 없을 정도로 쓰레드가 안전하지는 않습니다. 제 경우에는 그렇게하지 않을 것입니다. – djs22

+0

모듈은 "싱글 톤"이므로 모듈의 변수를 언제든지 변경할 수 있습니다 스레드를 안전하지 못한 스레드로 만듭니다. 내가 생각할 수있는 또 다른 방법은 실제로 가져올 때 다른 모듈의 클래스, 속성 및 인스턴스를 다시 작성하는 "복사기"모듈을 만드는 것입니다 - 모든 함수 전역 변수를 리 바인드합니다 (메서드는 여전히이 수준에서 함수로 처리됩니다).). – jsbueno

+0

그래, "복사기"모듈이 내가 필요로하는 것, 나는 이미 존재하는 것 같아 – djs22

-1

귀하의 질문은 여기에 설명 된 것 것과 매우 비슷합니다 상황에

File: config.py (your foo.py) 
x = 0 # Default value of the 'x' configuration setting 

File: mod.py (your foo2.py) 
import config 
config.x = 1 

File: main.py 
import config 
import mod 
print config.x # Prints 1 

http://effbot.org/pyfaq/how-do-i-share-global-variables-across-modules.htm 아마 다음 작업을 수행 할 수 있습니다 :이 당신의 코드 인 경우

#foo module 
SANITIZE = 'foo' 
def parse(): 
    print SANITIZE 

#foo2 module 
import foo 
foo.SANITIZE = 'foo2' 

#test script 1 
import foo 
foo.parse() # Prints 'foo' 

#test script 2 
import foo 
import foo2 
foo.parse() # Prints 'foo2' 
+0

감사합니다. sgallen, 불행히도 그것은 내가 원하는 것을 성취하지 못합니다. 코드에서 동일한 스크립트 내에서 foo와 foo2 사이를 전환 할 수 없습니다. – djs22

관련 문제