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                             

我没有机会从上面继承一个类,因为在我调用它之前这是函数。classmethods 有同样的问题,函数没有 classmethods。

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__,但这绝对是另一回事......

4

4 回答 4

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__()执行单例魔术的重写方法。这个类是可子类化的。

然而,几乎没有任何理由要创建单例。通常它只是一种隐藏全局状态的方法,可以更好地消除它。

于 2012-11-26T22:56:06.317 回答
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
>>> 
于 2012-11-26T23:47:55.420 回答
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 的回答和评论的启发,我找到了另一个解决方案。顺便说一句,单例只是一个例子,它与问题没有真正的关系。

于 2012-11-29T15:47:36.647 回答
0

为了能够从装饰类继承,您必须确保装饰器返回装饰类本身而不是包装器。__new__()您可以通过重载-operator来操作从此类创建新对象。通过这样做,如果装饰器本身是一个类,您甚至可以调用装饰器方法。当然,您也可以对装饰器使用继承。

有关完整示例,请参见

从装饰类继承

于 2015-10-01T07:51:24.610 回答