从装饰类继承
Posted
技术标签:
【中文标题】从装饰类继承【英文标题】:Inheriting from decorated classes 【发布时间】:2011-11-20 14:18:14 【问题描述】:我正在尝试用另一个班级装饰一个班级。我也想,但我得到了一些错误。这是我的代码:
class Decorator:
def __init__(self, decorated):
pass
@Decorator
class Foo:
pass
class Goo(Foo):
pass
当我尝试从Foo
子类化时得到的错误是:
回溯(最近一次通话最后一次): 文件“test.py”,第 9 行,在 类咕(Foo): TypeError: __init__() 正好采用 2 个位置参数(给定 4 个)
通过向Decorator
添加另一个初始化函数...
def __init__(self, *args):
for arg in args:
print(arg)
...我得到以下输出:
咕 (<__main__.decorator object at>,) '__module__': '__main__'
这些参数是什么?我应该如何在Decorator
中使用它们?
【问题讨论】:
【参考方案1】:我将尝试回答“这些参数是什么”的问题。这段代码:
@Decorator
class Foo:
pass
相当于:
class Foo:
pass
Foo = Decorator(Foo)
这意味着Foo
最终成为Decorator
类的实例,而不是一个类。
当您尝试将此实例用作类的基类 (Goo
) 时,Python 必须确定一个元类,用于创建新类。在这种情况下,它将使用等于Decorator
的Foo.__class__
。然后它将使用(name, bases, dict)
参数调用元类并期望它返回一个新类。
这就是你在Decorator.__init__
中最终得到这些参数的方式。
可以在此处找到有关此内容的更多信息: http://www.python.org/download/releases/2.2.3/descrintro/#metaclasses (特别是“当执行类语句时......”部分)
【讨论】:
【参考方案2】:您是否尝试在定义类之后向该类添加 MixIn? 如果是这样,您可以通过这种方式注入 MixIn:
def inject_class(mixin):
def _inject_class(cls):
return type(cls.__name__,(mixin,)+cls.__bases__,dict(cls.__dict__))
return _inject_class
class MixIn(object):
def mix(self):
print('mix')
@inject_class(MixIn)
class Foo(object):
def foo(self):
print('foo')
class Goo(Foo):
def goo(self):
print('goo')
goo=Goo()
goo.mix()
goo.foo()
goo.goo()
打印
mix
foo
goo
如果你不想要inject_class
的通用性,你可以制作一个专门的类装饰器,它只混入Decorator
:
def decorate(cls):
class Decorator(object):
def deco(self):
print('deco')
return type(cls.__name__,(Decorator,)+cls.__bases__,dict(cls.__dict__))
@decorate
class Foo(object):
def foo(self):
print('foo')
结果是一样的。
【讨论】:
【参考方案3】:我遇到了同样的问题,以下解决方案对我有用:
from functools import update_wrapper
class decoratorBase():
def __new__(cls, logic):
self = object.__new__(cls)
self.__init__(logic)
def new (cls):
#cls is the decorated class type, not the decorator class type itself
self._createInstance(cls)
self._postInstanceCreation()
return self
self._logic.__new__ = new
#return the wrapped class and not a wrapper
return self._logic
def __init__(self, logic):
#logic is the decorated class
self._logic = logic
def _createInstance(self, cls):
self._logicInstance = object.__new__(cls)
self._logicInstance.__init__()
def _postInstanceCreation(self):
pass
class factory(decoratorBase):
def __init__(self, *largs, **kwargs):
super().__init__(*largs, **kwargs)
self.__instance = None
def _createInstance(self, cls):
self._logicInstance = None
self._cls = cls
def _postInstanceCreation(self):
update_wrapper(self, self._cls)
def __call__(self, userData, *largs, **kwargs):
logicInstance = object.__new__(self._cls)
logicInstance.__init__(*largs, **kwargs)
logicInstance._update(userData)
return logicInstance
class singelton(decoratorBase):
def _postInstanceCreation(self):
update_wrapper(self, self._logicInstance)
def __call__(self, userData):
self._logicInstance._update(userData)
return self._logicInstance
class base():
def __init__(self):
self.var = 0
print ("Create new object")
def __call__(self):
self.var += self._updateValue()
def _update(self, userData):
print ("Update object static value with 0".format(userData))
self.var = userData
@factory
class factoryTestBase(base):
def __call__(self):
super().__call__()
print("I'm a factory, here is the proof: 0".format(self.var))
def _updateValue(self):
return 1
class factoryTestDerived(factoryTestBase):
def _updateValue(self):
return 5
@singelton
class singeltonTestBase(base):
def __call__(self):
super().__call__()
print("I'm a singelton, here is the proof: 0".format(self.var))
def _updateValue(self):
return 1
class singeltonTestDerived(singeltonTestBase):
def _updateValue(self):
return 5
这种方法的神奇之处在于 __new__()
方法的重载,对于装饰器本身以及装饰器返回的“包装器”也是如此。我将单词包装器放在引号中,因为实际上没有包装器。相反,装饰类由装饰器交替并返回。使用此方案,您可以从装饰类继承。最重要的是修饰类的__new__()
方法的变化,由以下几行组成:
def new (cls):
self._createInstance(cls)
self._postInstanceCreation()
return self
self._logic.__new__ = new
使用它,您可以在从装饰类创建对象期间访问装饰器方法,例如self._createInstance()
。您甚至有机会从您的装饰器继承(如示例中所示)。
现在让我们运行一个简单的例子:
>>> factoryObjCreater = factoryTestBase()
>>> factoryObj1 = factoryObjCreater(userData = 1)
Create new object
Update object static value with 1
>>> factoryObj2 = factoryObjCreater(userData = 1)
Create new object
Update object static value with 1
>>> factoryObj1()
I'm a factory, here is the proof: 2
>>> factoryObj2()
I'm a factory, here is the proof: 2
>>> factoryObjDerivedCreater = factoryTestDerived()
>>> factoryObjDerived1 = factoryObjDerivedCreater(userData = 2)
Create new object
Update object static value with 2
>>> factoryObjDerived2 = factoryObjDerivedCreater(userData = 2)
Create new object
Update object static value with 2
>>> factoryObjDerived1()
I'm a factory, here is the proof: 7
>>> factoryObjDerived2()
I'm a factory, here is the proof: 7
>>> singeltonObjCreater = singeltonTestBase()
Create new object
>>> singeltonObj1 = singeltonObjCreater(userData = 1)
Update object static value with 1
>>> singeltonObj2 = singeltonObjCreater(userData = 1)
Update object static value with 1
>>> singeltonObj1()
I'm a singelton, here is the proof: 2
>>> singeltonObj2()
I'm a singelton, here is the proof: 3
>>> singeltonObjDerivedCreater = singeltonTestDerived()
Create new object
>>> singeltonObjDerived1 = singeltonObjDerivedCreater(userData = 2)
Update object static value with 2
>>> singeltonObjDerived2 = singeltonObjDerivedCreater(userData = 2)
Update object static value with 2
>>> singeltonObjDerived1()
I'm a singelton, here is the proof: 7
>>> singeltonObjDerived2()
I'm a singelton, here is the proof: 12
>>>
【讨论】:
以上是关于从装饰类继承的主要内容,如果未能解决你的问题,请参考以下文章