2010-03-23 113 views
6

我有一個裝飾功能(簡化版):添加裝飾功能的一類

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學前班。

ROOT.TChain.DrawPlot = _DrawPlot 

當我把這個方法:

chain = TChain() 
chain.DrawPlot(opts) 

我:

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

爲什麼沒有傳播的自我?

+0

總是從'object'繼承,而不是什麼都不做,所以你使用的是新式的類。 – 2010-03-23 16:27:01

+0

如果您在此問題上有任何選擇,請勿使用大寫的首字母來命名方法。使用像'_draw_plot'(由PEP 8推薦)或'_drawPlot'這樣的名字。 – 2010-03-23 17:19:01

+0

我的回答是誤導,所以它得到了印章。感謝Mike的反饋! – 2010-03-23 17:39:39

回答

3

問題是,您已經定義了您自己的可調用類,然後嘗試將其用作方法。當你使用一個函數作爲屬性時,作爲一個屬性訪問該函數稱其爲__get__方法來返回除函數本身之外的東西 - 綁定方法。當你有自己的班級而沒有定義__get__時,它只是返回你的實例而不隱式傳遞self

如果您不熟悉描述符,則在http://docs.python.org/reference/datamodel.html#descriptors上解釋一些描述符。 __get____set____delete__方法改變了作爲屬性起作用時與對象的交互方式。


您可以實現memoize的功能,並使用內置的__get__魔法功能已經

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 

或沿

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) 

注行修改你的類如果你傳入的任何參數都是可變的(這在技術上是不可能的),這兩個都會窒息。這可能適合您的情況,但您也可能想要處理args不可用的情況。

+0

我更喜歡第二個版本,因爲我可以控制緩存,我可以爲不同的功能創建多個Memorize對象以及不同的緩存。 我正在使用更復雜的'hash = args',因爲我需要處理可變對象。正如你所說的「哈希」不是一個很好的名字。 – 2010-03-23 19:25:10

+0

@wiso,第一個代碼示例對於您記憶的每個函數都會有不同的緩存。在記憶中總是要小心處理可變類型;他們不可能有很好的理由。你必須瞭解被記憶的函數的作用方式是否知道它是否有問題。 – 2010-03-23 20:01:59

+0

抱歉,但你的解決方案不起作用: @Memoize 高清功能(自我,X): 打印自 返回X * X 類my_class: 通 my_class.do =功能 C = my_class () print c。(2) TypeError:function()只需要2個參數(1給出) – 2010-03-24 09:33:13