2011-05-16 2 views
4

어떻게하면 이런 장식을 쓸 수 있을까요? 나는 decorator를 호출 할 때 max_hits의 값을 지정할 수 있기를 원한다.Python - 클래스 기반 데코레이터에 선택적 인수를 지정하는 방법은 무엇입니까?

예, 원하는 사용이 될 것

@memoize(max_hits=7) 
def a(val): 
    print val 

또는

@memoize 
def a(val): 
    print val 

(첫 번째 예제를 사용하여 잘못된 인수에 대한 오류를 제공합니다.)

실내 장식 :

class memoize: 
    """A decorator to cache previosly seen function inputs. 

    usage: 
     @memoize 
     def some_func(.. 
    """ 
    def __init__(self, function, max_hits=None): 
     self.max_hits = max_hits 
     self.function = function 
     self.memoized = {} 

    def __call__(self, *args, **kwargs): 
     key = (args,tuple(kwargs.items())) 
     try: 
      return self.memoized[key] 
     except KeyError: 
      self.memoized[key] = self.function(*args,**kwargs) 
     return self.memoized[key] 
+0

왜 모든 사람이 메모를 남깁니 까. –

+0

@Jakob Bowyer : http://en.wikipedia.org/wiki/Memoization#Etymology – mouad

+0

[Python에서 선택적 인수가있는 클래스 정의] 가능한 복제본 (https://stackoverflow.com/questions/10681038/define-a) -class-with-optional-argument-in-python) –

답변

8

memoize함수을 선택적 인수 max_hits을 사용하고 장식을 반환해야합니다 (예 : 첫 번째 인수로 함수를 사용하는 다른 호출 가능 객체); 그래서

@memoize() 
def func(x): 
    [...] 

@memoize(max_hits=7) 
def func(x): 
    [...] 

의 라인을 따라 아마도 뭔가 :이 경우, 다음과 같은 두 가지 구문 사용할 수 있습니다 @memoize()가 작동하지만 원래 @memoize 구문은하지 않습니다 원하는 것을

def memoize(max_hits=None): 
    """Returns a decorator to cache previosly seen function inputs. 

    usage: 
    @memoize() 
    def some_func(.. 
    """ 
    class decorator: 
     def __init__(self, function): 
      self.max_hits = max_hits 
      self.function = function 
      self.memoized = {} 

     def __call__(self, *args, **kwargs): 
      key = (args,tuple(kwargs.items())) 
      try: 
       return self.memoized[key] 
      except KeyError: 
       self.memoized[key] = self.function(*args,**kwargs) 
      return self.memoized[key] 

    return decorator 

참고; 후자의 경우 @memoize으로 꾸미는 함수는 첫 번째 인수 (max_hits)로 memoize으로 전달됩니다. 당신이이 사건을 처리하려면 다음과 같이 memoize을 확장 할 수 있습니다 :

def memoize(max_hits=None): 
    if callable(max_hits): 
     # For sake of readability... 
     func = max_hits 
     decorator = memoize(max_hits=None) 
     return decorator(func) 
    [...original implementation follows here...] 
+0

내 데코레이터가 클래스를 반환하겠습니까? – Greg

+0

예; 위의 확장 예제를 참조하십시오. –

3

이 3.2 이상을 사용하는 경우는, 그것을 직접 작성하지 않는, 당신은을 지원하려면 from functools import lru_cache 대신

를 사용 "괄호 안 함"버전을 사용하는 경우 "잘못된"인수를 관 {하는 것이 아니라 함수 인수에 센티널 값을 사용하는 것이 더 좋습니다. 즉 :

class Memoized(object): 
    # As per the memoize definition in the question 

# Leave out the "*, " in 2.x, since keyword-only arguments are only in 3.x 
from functools import partial 
_sentinel = object() 
def memoize(_f=_sentinel, *, max_hits=None): 
    if _f is _sentinel: 
     return partial(Memoized, max_hits=max_hits) 
    return Memoized(_f, max_hits=max_hits) 
+1

무언가를 downvote하려고한다면, 왜 * why *라고 말하는 것이 예의입니다. 여기에 설명 된 감시 기술은 하나의 함수가 데코레이터 팩토리 ('@memoize (max_hits = 7)'또는'@memoize()')와 데코레이터 ('@ memoize')의 역할을하도록하는 가장 강력한 방법입니다. – ncoghlan

관련 문제