2012-11-26 98 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