2011-01-10 7 views
7

그것이 어떻게 호출되는지는 알지만 필자를 위해 예제를 제공 할 것입니다.데코레이터 클래스와 데코레이터 함수의 차이점

데코레이터 클래스 :

class decorator(object): 
    def __init__(self, func): 
     self.func = func 

    def __call__(self, *args, **kwargs): 
     print 'something' 
     self.func(*args, **kwargs) 

데코레이터 기능 :

def decorator(func): 
    def wrapper(*args, **kwargs): 
     print 'something' 
     return func(*args, **kwargs) 
    return wrapper 

하나 맛의 다른 단지 문제를 사용? 실용적인 차이점이 있습니까?

+3

차이가 있습니다. 그 차이는 일반 함수 대 일반 클래스를 사용하고자 할 때 정확히 동일합니다. – Falmarri

답변

10

데코레이터를 구현하는 함수를 작성할 수 있으면 선호해야합니다. 그러나 일부 내부 상태를 저장하려는 경우와 같이 모든 데코레이터를 함수로 쉽게 작성할 수있는 것은 아닙니다. (자신 포함)

class counted(object): 
    """ counts how often a function is called """ 
    def __init__(self, func): 
     self.func = func 
     self.counter = 0 

    def __call__(self, *args, **kwargs): 
     self.counter += 1 
     return self.func(*args, **kwargs) 


@counted 
def something(): 
    pass 

something() 
print something.counter 

내가 본 사람들은 기능과 장식을 쓸 말도 노력을 통해 이동합니다. 왜 클래스의 오버 헤드가 대개는 거의 무시할 수 있는지는 아직 알 수 없습니다.

+4

물론 이것은 * 함수로 쓰여질 수 있습니다. 그러나 파이썬에서는 일반적으로 상태를 숨기기 위해 클로저보다 클래스를 선호합니다. –

+1

@Sven : 당신 말이 맞아, 나는 정말로 거기에 과장했다. –

+1

필자는 실제로 파이썬 (3.x) 버전을 좋아한다. (주석은 줄 바꿈을하기 때문에 중괄호 \ * sob \ *를 사용한다.) def counted (f) {x = 0; def wrapper (* args, ** kwargs) {nonlocal x; x + = 1; f (* args, ** kwargs)} 래퍼 리턴}'. 2.x 버전은 단조롭지 만 (싱글 톤 목록을 사용하고 단일 항목을 사용하여 '비 로컬 (nonlocal)'부족을 해킹합니다). – delnan

3

일반적으로 맛의 문제입니다. 대부분의 파이썬 프로그램은 오리 타이핑을 사용하며 호출 할 수있는 한 그들이 호출하는 것이 함수인지 또는 다른 유형의 인스턴스인지 여부를 실제로 신경 쓰지 않습니다. 그리고 __call__() 메서드를 가진 어떤 것도 호출 가능합니다.

  • 래퍼 함수를 ​​반환하지 않는 장식 (즉, 그것으로 뭔가를하고 후 원래의 함수를 반환

    많은 청소기 등에게 :

    기능 스타일의 장식을 사용하는 몇 가지 장점이 있습니다 속성 설정).

  • 원래 함수에 대한 참조를 클로저에서 명시 적으로 저장할 필요가 없습니다. 당신을 도울 수있는 도구의 대부분

  • 는 장식을 같은 functools.wraps() 또는 미셸 SIMIONATO의 서명 보존 decorator 모듈, 기능 스타일의 장식과 함께 일을.

  • 오리 타이핑을 사용하지 않지만 실제로 함수 유형을 예상하는 일부 프로그램이있을 수 있으므로 함수를 대체하는 함수를 반환하는 것은 이론적으로 "안전합니다".

이러한 이유로 대부분의 경우 함수 스타일 데코레이터를 사용합니다. 반례로, here은 클래스 스타일 데코레이터가 내게 더 자연 스럽다는 최근 사례입니다.

+2

'functools.wraps()'는 함수 스타일 꾸미기와 함께 동작하지만, 클래스 스타일 꾸미기의'__init__'에있는'functools.update_wrapper (self, wrapped)'가 작동하도록 의도되었을 수도 있습니다. 완벽하게. –