2013-07-30 1 views
3

파이썬 장식자를 사용하여 함수를 "비활성화"할 수 있습니까? 여기에 예 : 도서관에서 옵션 (하기 matplotlib 같은) 일부 종속성이 있으며, 이들은 다음과 같습니다데코레이터로 함수 비활성화

cond = False 

class C: 

    if cond: 
     def x(self): print "hi" 

    def y(self): print "ho" 

는이

class C: 

    @cond 
    def x(self): print "hi" 

    def y(self): print "ho" 

배경? :처럼 장식이 코드를 다시 작성하는 것이 가능 몇 가지 기능 만 필요합니다 (디버그 또는 정면). 이것은 어떤 시스템에서는 matplotlib가 다른 시스템에 설치되지 않았 음을 의미하지만 둘 다 (코어) 코드를 실행해야합니다. 그러므로 matplotlib가 설치되지 않은 경우 일부 기능을 비활성화하고 싶습니다. 그런 우아한 방법이 있습니까?

+0

이 왜 그렇게해야? 추가 기능은 거의 자원을 차지하지 않습니다. 이 메소드는 비활성화 된 경우 속성 오류를 발생시켜야합니까? –

+1

'disable'을 정의하십시오. 함수를 아무 작업으로 바꾸는 것을 의미하는 경우, 이것은'lambda _ _ : None'을 반환하는 데코레이터로 할 수 있습니다. – l4mpi

+0

가장 좋은 경우에는 그들이 사라지거나 matplotlib이 설치되어 있지 않음을 기록하십시오. – Themerius

답변

12

당신은 어떤 작전으로 기능을 설정 할 수있는 장식으로 (즉, 경고 로그) :

def conditional(cond, warning=None): 
    def noop_decorator(func): 
     return func # pass through 

    def neutered_function(func): 
     def neutered(*args, **kw): 
      if warning: 
       log.warn(warning) 
      return 
     return neutered 

    return noop_decorator if cond else neutered_function 
여기

conditional는 장식 공장입니다. 조건에 따라 두 개의 데코레이터 중 하나를 반환합니다.

하나의 데코레이터는 단순히 기능을 그대로 둡니다. 다른 데코레이터는 데코 레이팅 된 기능을 대체하여 경고를 대신 표시합니다.

사용 :

@conditional('matplotlib' in sys.modules, 'Please install matplotlib') 
def foo(self, bar): 
    pass 
+0

'matplotlib'을'func'에 삽입 할 수 있습니까? – Themerius

+0

그리고 주사는 * 무엇을 의미할까요? 'func' 자체는 변경할 수 없습니다. 당신은'func'을 ('func'을 호출하는 래퍼로 또는 결과를 생성하기 위해) 대체 할 수 있습니다 만,'func' 자체의 코드를 변경할 수는 없습니다. –

+1

아니면 정말로 가고 싶다면 디 컴파일이나 AST 트리 변환이 필요합니다. 당신은 일반적으로 거기에가는 것을 피하려고합니다. –

2

Martijns이 noops에 기능을 tunring와 거래 대답, 당신이 실제로 클래스에서 제거하는 방법을 설명하겠습니다 - 아마 잔인한 사람입니다, 제가 정착 것 어떤 종류의 예외를 throw하는 Martijns 응답의 변형입니다. 하지만 어쨌든 :

클래스 데코레이터를 사용하여 영향을받은 함수를 클래스에서 제거 할 수 있습니다. 이 사람은 제거 부울 및 속성의 목록을 취

def rm_attrs_if(cond, attrs): 

    if not cond: 
     return lambda c: C#if the condition is false, don't modify the class 

    def rm_attrs(cls): 
     d = dict(cls.__dict__) #copy class dict 
     for attr in attrs: 
      del d[attr]  #remove all listed attributes 
     return type(cls.__name__, cls.__bases__, d) #create and return new class 

    return rm_attrs 

이처럼 사용

@rm_attrs_if(something == False, ["f1", "f2"]) 
class X(): 
    def f1(): pass 
    def f2(): pass 
    def f3(): pass 
+0

왜 장식 자에 새 클래스를 만드시겠습니까? 제 생각에 att attr에 delattr (cls, attr)을 쓰고 cls를 반환하는 것이 더 쉬울 것이라고 생각합니다. –

+0

@SvenMarnach 습관의 힘, 내 생각 엔 - 새로운 클래스를 파이썬으로 동적으로 생성하는 것은 기존 클래스의 특성을 제거하는 것이 었습니다. 이 접근법의 장점은 데코레이터를 사용하여 기존 클래스의 클래스를 비파괴 적으로 파생시킬 수 있다는 것입니다. 'B = rm_attrs_if (flag, attrs) (A)'는'A'를 바꾸지 않고 새로운 클래스'B'를 만듭니다. – l4mpi

관련 문제