2014-02-20 91 views
0

不知道這是否是一個適當的問題,但這裏是問題所在。更改子類中的裝飾參數

我有一個memoized裝飾(作爲一個類實現)。裝飾器接受一個參數,它是緩存的大小。我想我的數據庫模型類各有一個搜索方法,所以我寫一個mixin(我認爲這是一個混合)

class SearchMixin(object): 
    @classmethod 
    @memoized(100) 
    def search(cls,session,**kwargs): 
     q = session.query(cls) 
     for k,v in kwargs.items(): 
      q = q.filter(getattr(cls,k,None).__eq__(v)) 
     res = q.one() 
     return res 

而且在我的模型,

class ModelA(Base,SearchMixin): 
    foo = Column() 
    bar = Column() 
    #And so on 

現在我可以做一個ModelA.search(foo=x,bar=y)並且memoized裝飾器工作並從緩存中返回,前提是之前詢問過相同的查詢。

問題是,對於某些型號,我需要更改某些搜索的緩存大小(這是100中的SearchMixin)。我可以重新編寫使用不同的參數搜索功能的裝飾

class ModelB(Base): 
    @classmethod 
    @memoized(5) 
    def search(cls,session,**kwargs): 
     #Search method for my modelB 

但擊敗寫混入(去除重複代碼)的目的。

我非常想要的是

class ModelB(Base,SearchMxin): 
    foo1 = Column() 
    bar1 = Column() 
    cache_size = 5 
    #Some magic 
    #Now I don't need to rewrite the search function with a different argument 

是否有實現這一目標的方法嗎?它甚至是一種有效的使用方式嗎?

+0

你可以通過編寫一個不同的memoization裝飾器來實現它,它在調用時從類屬性中讀取它的緩存大小,而不是在定義時從參數中讀取它。 – BrenBarn

回答

3

這裏的一種方式的草圖:

def deco(func): 
    def newFunc(cls, *args, **kw): 
     print "Decorated function using cache size", cls.cache_size 
     return func(cls, *args, **kw) 
    return newFunc 

class Foo(object): 
    cache_size = 10 

    @classmethod 
    @deco 
    def meth(cls): 
     print "Foo.meth()" 

class Bar(Foo): 
    cache_size = 20 

>>> Foo.meth() 
Decorated function using cache size 10 
Foo.meth() 
>>> Bar.meth() 
Decorated function using cache size 20 
Foo.meth() 

我不知道你的記憶化裝飾究竟是幹什麼的,所以這個例使用的是虛擬裝飾。但是這個想法應該是清楚的:編寫你的裝飾器,以便它在類上查找它的緩存大小,而不是將緩存大小作爲參數傳遞。

只是爲了澄清事情:在你的榜樣,當你在SearchMixin創建search方法和應用@memoize(100),「原始」的搜索方法---即,未加裝飾的版本沒有記憶化---有效不復存在。如果緩存大小在裝飾器調用時是固定的,那麼只能通過分配一個類變量,您不能回到內部並稍後進行修改。最終,您需要以某種方式重構裝飾器,以便從某個外部源(例如,類)中檢索所需的緩存大小。 (如果你的memoization裝飾器實際上是一個類,它可能會使它更聰明和偷偷摸摸,這樣它會注意到它是否會「重新裝飾」一個已經用相同裝飾器包裝的方法。在這種情況下,memoization類可以修改其內部緩存大小變量,而不是添加另一層包裝,但是很難說這將如何工作,或者如何與其他裝飾器進行交互,而不知道如何使用memoization裝飾器當前運行。)

+0

這是一個好主意。但我的裝飾器是一個類(不是函數),並接受一些參數(調試和東西)。它也可以用於任意函數(不僅僅是類方法)。目前我不會將該類傳遞給裝飾器(只是函數) – RedBaron

+1

@RedBaron:如果您對裝飾器有其他限制,則需要編輯您的問題以解釋它們。我在這裏給出的解決方案可以很容易地使用類而不是函數來完成,並且可以接受額外的參數。然而,我不認爲編寫一個適用於類方法和獨立函數的裝飾器是有很多希望的,但仍然會在類中尋找它的高速緩存大小。如果你想讓裝飾器使用類似'cache_size'的類變量,裝飾器需要與類有一定程度的整合。 – BrenBarn