Skip to main content
 首页 » 编程设计

python之装饰类继承和类方法

2025年05月04日11dyllove98

如何以正确的方式装饰一个类,以便能够从被装饰的类继承一个类?有没有正确的方法?

如果我会做这样的事情:

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同样的问题,function没有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__ 修改类实例,但这绝对是另一回事...

请您参考如下方法:

您的装饰器需要返回原始类(或其子类)才能进一步子类化。您的装饰器在用作装饰器时返回其自身的一个实例(因为这是调用类的默认行为)。

例如,像这样:

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__() 方法,该方法执行单例魔术。这个类是可继承的。

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