2012-11-26 145 views
2

如何以正確的方式裝飾類以便能夠從裝飾類繼承類?有沒有正確的方法?裝飾類繼承和類方法

如果我會做這樣的事情:

def singleton(cls):        
    inst = {}         
    def get(*args, **kwargs):     
     cls_id = id(cls)      
     if cls_id not in inst:     
      inst[cls_id] = cls(*args, **kwargs) 
     return inst[cls_id]      
    return get 


@singleton 
class A(object): 
    @classmethod 
    def cls_meth(cls): 
     return cls        

我有沒有機會繼承一個以上的一類,因爲之前我把它稱作是這樣的功能。與類方法相同的問題,函數沒有類方法。

class B(A): # No way! `A` is the function! 
    pass 

A.cls_meth() # AttributeError: 'function' object has no attribute 'cls_meth'  

即使我做這樣的事情:

class SingletonDecorator(object):       
    inst = {}            
    def __init__(self, cls):        
     self.cls = cls         

    def __call__(self, *args, **kwargs):     
     cls_id = id(self.cls)        
     if cls_id not in self.inst:      
      self.inst[cls_id] = self.cls(*args, **kwargs) 
     return self.inst[cls_id]       


@SingletonDecorator 
class A(object): 
    pass 

當我從A類繼承一個類時,它會從SingletonDecorator類,而不是A繼承。

class B(A): # No no no! I do not need a `SingletonDecorator` child class... 
    pass 

有通過__metaclass__修改類實例的方式,但卻是完全另一回事了

+2

這是不相關的問題,但沒有必要使用'ID()'一類的字典鍵,你可以只使用類本身(類可哈希)。 – kindall

回答

1

你的裝飾需要返回原來的類(或它的子類)才能將其進一步細分。作爲裝飾器使用時,你的裝飾器返回自身的一個實例(因爲這是調用類的默認行爲)。

例如,這樣的事情:

def singleton(cls): 
    class C(cls): 
     _instance = None 
     def __new__(c, *args, **kwargs): 
      if type(c._instance) != c: 
       c._instance = cls.__new__(c, *args, **kwargs) 
      return c._instance 
    C.__name__ = cls.__name__ 
    return C 

這將返回原始類的子類具有覆蓋__new__()方法,做單身的魔法。這個類是可分類的。

但是,幾乎沒有任何理由創建單例。通常,這只是一種隱藏全局狀態的方式,可以更好地消除。

0

你的裝飾器需要返回一個類,以便你繼承它。鑑於這一結果

>>> def decorator(cls): 
...  class Stuff(cls): 
...   @classmethod 
...   def print_result(kls): 
...    print 'results= %s' % kls.results 
...  return Stuff 
... 
>>> class Foo(object): 
...  results = 'grade A' 
...  @classmethod 
...  def print_result(cls): 
...   print cls.results 
... 
>>> 
>>> @decorator 
... class Bar(Foo): 
...  pass 
... 
>>> class Baz(Bar): 
...  def frobnicate(self): 
...   pass 
... 
>>> 
>>> Baz.print_result 
<bound method type.print_result of <class '__main__.Baz'>> 
>>> Baz.print_result() 
results= grade A 
>>> Foo.print_result 
<bound method type.print_result of <class '__main__.Foo'>> 
>>> Foo.print_result() 
grade A 
>>> 
0

想法:

class SD(object):           
    """ The right way to decorate classes """    
    inst = {}            
    def __init__(self, cls):        
     self.__dict__.update(cls.__dict__)     
     self.__name__ = cls.__name__      
     self.cls = cls          

    def __call__(self, *args, **kwargs):     
     if self.cls not in self.inst:      
      self.inst[self.cls] = self.cls(*args, **kwargs) 
     return self.inst[self.cls]       

啓發@kindall的回答和評論,我來到了另一種解決方案。順便說一句,單身人士只是一個例子,它對問題沒有真正的影響。

0

爲了能夠從裝飾類繼承,您必須確保裝飾器本身返回裝飾類而不是包裝器。您可以通過重載__new__()操作員來操作從此類創建的新對象。通過這樣做,如果裝飾器本身是一個類,你甚至可以調用裝飾器方法。當然,你也可以使用裝飾器的繼承。

對於一個完整的例子看

Inheriting from decorated classes