2013-02-07 2 views
1

트위스트 된 위에 파이썬 프로젝트의 코드를 리펙토링하려고합니다.파이썬에서 구성 변경 사항을 동적으로 브로드 캐스트합니다.

#settings.py 
MY_CONSTANT='whatever' 
A_SLIGHTLY_COMPLEX_CONF= {'param_a':'a', 'param_b':b} 

모듈의 큰 거래는 자신의 물건을 할 settings.py을 가져옵니다 지금까지 내가 좋아하는 상수와 사전을 저장하는 간단한 settings.py 모듈을 사용하고있다.

프로젝트를 리팩터링하려는 이유는 설정 매개 변수를 변경/추가해야하기 때문입니다. 내가 취하려고하는 접근법은 싱글 톤에서 모든 구성을 수집하고 필요할 때마다 인스턴스에 액세스하는 것입니다.

import settings.MyBloatedConfig 

def first_insteresting_function(): 
    cfg = MyBloatedConfig.get_instance() 
    a_much_needed_param = cfg["a_respectable_key"] 
    #do stuff 

#several thousands of functions later 

def gazillionth_function_in_module(): 
    tired_cfg = MyBloatedConfig.get_instance() 
    a_frustrated_value = cfg["another_respectable_key"] 
    #do other stuff 

이 접근법은 효과가 있지만 부 자연스러운 느낌이납니다. 대안은 다음과 같이 모듈에 cfg 객체를 구체화하는 것입니다 : 내가 다른 모듈에 MyBloatedConfig 인스턴스 항목을 변경하고있는 경우

CONFIG=MyBloatedConfig.get_instance() 

def a_suspiciously_slimmer_function(): 
    suspicious_value = CONFIG["a_shady_parameter_key"] 

불행하게도이 작동하지 않습니다. 원자로 패턴을 사용하기 때문에 스레드 로컬에 직원을 저장하는 것은 문제가되며 대기열을 사용하는 것입니다. 구현 내가 싱글 톤 패턴

instances = {} 
def singleton(cls): 
    """ Use class as singleton. """ 
    global instances 

    @wraps(cls) 
    def get_instance(*args, **kwargs): 
     if cls not in instances: 
      instances[cls] = cls(*args, **kwargs) 
     return instances[cls] 
    return get_instance 

@singleton 
class MyBloatedConfig(dict): 
    .... 

다른 모듈에서 구성 변경 내용을 방송하는 다른 많은 파이썬 방법이 있나요을 구현하기 위해 사용하고있다 다음과 완전성에 대해

?

답변

2

큰 글로벌 (대개 싱글 톤) 구성 객체는 안티 패턴입니다.

settings.py, MyBloatedConfig.get_instance() 스타일의 싱글 톤 또는 여기에 설명 된 다른 접근 방식 중 어느 것을 사용하든 기본적으로 동일한 반 패턴을 사용합니다. 정확한 철자는 중요하지 않습니다. 이것은 전체 프로젝트의 모든 코드에서 공유하는 진정한 글로벌 (파이썬 모듈 수준의 글로벌과는 다른)을 갖는 모든 방법 일뿐입니다.

  • 그것은 단위 테스트 코드를 어렵게 만든다 :

    은 여러 가지 이유로 안티 패턴이다. 이 글로벌을 기반으로 동작을 변경하는 모든 코드는 여러 가지 해킹을 필요로 할 것입니다. 예를 들어 원숭이 패치를 사용하면 여러 구성에서 동작을 단위 테스트 할 수 있습니다. 이를 함수 인수와 같이 인수를 받아들이도록 작성된 코드와 비교하여 전달 된 값을 기반으로 동작을 변경합니다.
  • 코드를 재사용하지 않아도됩니다. 구성이 전역 적이므로 두 가지 구성에서 해당 구성 개체를 사용하는 코드를 사용하려면 고리를 뛰어 넘어야합니다. 귀하의 싱글 톤은 하나의 구성만을 나타낼 수 있습니다. 그래서 당신은 당신이 원하는 다른 행동을하기 위해 앞뒤로 글로벌 상태를 교환해야 할 것입니다.
  • 코드를 이해하기 어렵게 만듭니다. 글로벌 구성을 사용하는 코드를보고 어떻게 작동하는지 알고 싶다면 구성을 살펴 봐야 할 것입니다. 그러나 이것보다 훨씬 더 나쁜 것은 설정을 바꾸고 싶을 때 전체 코드베이스를 조사하여 이것이 영향을 줄 수있는 코드를 찾아야한다는 것입니다. 이로 인해 새 항목을 추가하고 이전 항목을 자주 제거하거나 수정하기 때문에 무언가를 깨뜨릴 염려가 있거나 (예전 항목의 모든 사용자를 올바르게 추적 할 시간이 없음) 시간이 지남에 따라 구성이 커집니다.

위의 문제는 해결책이 무엇인지를 암시해야합니다. 어떤 상수의 값을 알아야하는 함수가 있다면, 그 값을 인수로 받아들이도록하십시오. 많은 양의 값을 필요로하는 함수가 있다면 편리한 컨테이너에 값을 저장하고 해당 클래스의 인스턴스를 함수에 전달할 수있는 클래스를 만듭니다.

사람들을 괴롭히는이 솔루션의 부분은이 모든 인수 전달을 타이핑하는 데 시간을 보내고 싶지 않은 부분입니다. 하나 또는 두 개의 (또는 심지어 제로) 인수를 취한 함수를 사용하기 전에 이제는 세 개 또는 네 개의 인수를 취해야하는 함수가 있습니다. settings.py 스타일로 작성된 응용 프로그램을 변환하는 경우 일부 기능에 전역 구성의 항목이 6 개 이상 사용되고 이러한 기능이 갑자기 긴 서명이 있음을 알 수 있습니다.

나는이 문제가 잠재적 인 문제는 아니지만 대부분 기존 코드의 구조와 구성에 대한 문제로보아야합니다. 상당히 긴 서명으로 끝나는 함수 이전의 모든 데이터에 의존합니다. 사실은 단지 당신에게서 가려져있었습니다. 그리고 프로그램의 측면을 숨기는 대부분의 프로그래밍 패턴과 마찬가지로 이것은 나쁜 것입니다. 이 모든 값을 명시 적으로 전달하면 추상화가 필요한 부분을 알 수 있습니다. 어쩌면 10 매개 변수 함수가 너무 많은 작업을 수행하고 있고 3 가지 다른 함수로 더 잘 작동 할 수도 있습니다. 또는 그 매개 변수의 절반이 실제로 관련되어 항상 컨테이너 객체의 일부로 함께 있다는 것을 알 수 있습니다. 아마도 이러한 매개 변수를 조작하는 것과 관련된 논리를 해당 컨테이너 객체에 배치 할 수도 있습니다.

+0

저는 싱글 톤 안티 패턴에 대해 잘 알고 있습니다 만, 제 경우에는 MyBlocatedConfig 글로벌 오브젝트 (간략히 설명하자면)는 제 어플리케이션의 핵심을 구현합니다. 'reactor' 객체와 비교할 수 있습니다. 'reactor'는 singleton twisted가 속박되어있다. 명시 적으로 함수 시그니처에 전달하지 말고 모듈을 가져 와서 (명시 적으로 모듈을 다시로드하지 않도록) 사용하십시오. 전 세계적인 물건을 가져오고 사용하지 않기 위해 제안을 환영하지만, 신청서에 무언가로 무언가를 가지고 서명을 오염시키지 않아도됩니다. – autholykos

+1

'원자로'가 하나의 실수라고 널리 여겨지고 있습니다. 이 실수를 수정하기위한 장기 계획이 있습니다. :) 그러나 전역 객체가 애플리케이션의 핵심이라고 말하면 나는 당신을 믿어야 만합니다. 그리고 나는 그 경우에 제안 할 것이 많지 않습니다, 그렇게 행운. –

+0

매우 흥미 롭습니다. 어쩌면 만약 당신이 저에게 장기 계획에 대한 몇 가지 문서를 가르키면 제 코드를 리팩토링하는 데 영감을 줄 수 있습니다. (아마도 기여할 수도 있습니다 :) – autholykos

관련 문제