2010-03-23 7 views
6

에 장식 기능을 추가 I가 장식 된 기능 (간단 버전) :클래스

class Memoize: 
    def __init__(self, function): 
     self.function = function 
     self.memoized = {} 
    def __call__(self, *args, **kwds): 
     hash = args 
     try: 
      return self.memoized[hash] 
     except KeyError: 
      self.memoized[hash] = self.function(*args) 
      return self.memoized[hash] 


@Memoize 
def _DrawPlot(self, options): 
    do something... 

가 지금은 전 esisting 클래스에이 방법을 추가 할.

chain = TChain() 
chain.DrawPlot(opts) 

는 내가 가진 :

self.memoized[hash] = self.function(*args) 
TypeError: _DrawPlot() takes exactly 2 arguments (1 given) 

왜 자기를 전파하지 않습니다 나는이 메소드를 호출

ROOT.TChain.DrawPlot = _DrawPlot 

?

+0

새로운 스타일의 클래스를 사용하도록 항상 객체 대신 상속합니다. –

+0

문제에 대한 선택 사항이있는 경우 대문자로 된 첫 글자로 메소드의 이름을 지정하지 마십시오. '_draw_plot' (PEP 8에서 권장)이나'_drawPlot'과 같은 이름을 사용하십시오. –

+0

내 대답은 오해의 소지가있어 절단이 발생했습니다. Mike에게 감사드립니다. –

답변

3

문제는 사용자가 직접 호출 가능한 클래스를 정의한 다음이를 메소드로 사용하려고했기 때문입니다. 함수를 속성으로 사용하면 해당 함수를 속성으로 액세스하면 __get__ 메서드가 호출되어 함수 자체 (바인딩 된 메서드) 이외의 것을 반환합니다. __get__을 정의하지 않고 클래스를 만들면 암시 적으로 self을 전달하지 않고 인스턴스를 반환합니다.

설명자가 익숙하지 않은 경우 http://docs.python.org/reference/datamodel.html#descriptors에 설명되어 있습니다. __get__, __set____delete__ 메서드는 속성으로 객체와 상호 작용하는 방식을 변경합니다.


당신은 내장 __get__ 마법 기능이 이미

import functools 

class Memoize(object): #inherit object 
    def __init__(self, function): 
     self.function = function 
     self.memoized = {} 
    def __call__(self, *args): #don't accept kwargs you don't want. 
     # I removed "hash = args" because it shadowed a builtin function and 
     # because it was untrue--it wasn't a hash, it was something you intended for 
     # Python to hash for you. 
     try: 
      return self.memoized[args] 
     except KeyError: 
      self.memoized[args] = self.function(*args) 
      return self.memoized[args] 
    def __get__(self, obj, type): 
     if obj is None: #We looked up on the class 
      return self 

     return functools.partial(self, obj) 

주의 라인을 따라 클래스를 수정하여

import functools 

def memoize(f): 
    @functools.wraps(f) 
    def memoized(*args, _cache={}): 
     # This abuses the normally-unwanted behaviour of mutable default arguments. 
     if args not in _cache: 
      _cache[args] = f(*args) 
     return _cache[args] 
    return memoized 

이상이 그 함수로 memoize를 구현하고 사용할 수 있습니다 두 인수 모두 당신이 전달하는 인수가 변경 가능하다면 (글쎄, 기술적으로는 해칠 수 없다). 이것은 귀하의 경우에 적합 할 수도 있지만, args이 해쉬 할 수없는 경우를 다루고 싶을 수도 있습니다.

+0

나는 캐시를 제어 할 수 있기 때문에 두 번째 버전을 선호한다. 하나 이상의 Memorize 객체를 생성 할 수 있고 다른 기능을 위해 매우 복잡한 캐시를 만들 수있다. 변경 가능한 객체를 처리해야하기 때문에 좀 더 복잡한 'hash = args'를 사용하고 있습니다. 당신이 말했듯이 "해쉬"는 아주 좋은 이름은 아닙니다. –

+0

@wiso, 첫 번째 코드 예제는 메모 한 모든 기능에 대해 다른 캐시를 사용합니다. memoization에서 변경 가능한 유형을 처리하기 위해 항상주의하십시오. 그들은 좋은 이유로 해시 가능하지 않습니다. 암기 된 기능이 버그인지 아닌지를 알기 위해 어떻게 작동하는지 이해해야합니다. –

+0

죄송합니다, 솔루션이 작동하지 않지만 : @Memoize DEF 기능 (자체, 배) : 인쇄 자기 반환 X * X 클래스 my_class : 패스 my_class.do = 기능 C = my_class() 인쇄 c.do (2) TypeError : function()이 정확히 2 개의 인수 (주어진 경우 1) –