如何以正确的方式装饰一个类,以便能够从装饰的类中继承一个类?是否存在正确的方法?
如果我会这样做:
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__
修改类实例,但这绝对是另一个故事......
答案 0 :(得分: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__()
方法执行单例魔术。这个类是可子类化的。
然而,几乎没有任何理由创建单身人士。通常它只是隐藏全局状态的一种方式,可以更好地消除。
答案 1 :(得分: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
>>>
答案 2 :(得分: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的回答和评论的启发,我来到了另一个解决方案。 顺便说一句,单身只是一个例子,它与这个问题没有关系。
答案 3 :(得分:0)
为了能够从装饰类继承,您必须确保装饰器返回装饰类本身而不是包装器。您可以通过重载__new__()
- 运算符来操纵此类中新对象的创建。通过这样做,如果装饰器本身是一个类,你甚至可以调用装饰器方法。当然,你也可以为装饰器使用继承。
有关完整示例,请参阅