2011-09-19 94 views
3

我试图用另一个类来装饰一个类。我也想从装饰类继承,但我得到一些错误。这里是我的代码:继承装饰类

class Decorator: 
    def __init__(self, decorated): 
     pass 

@Decorator 
class Foo: 
    pass 

class Goo(Foo): 
    pass 

我得到的,当我尝试从Foo子类错误是这样的:

Traceback (most recent call last):
   File "test.py", line 9, in
      class Goo(Foo):
TypeError: __init__() takes exactly 2 positional arguments (4 given)

通过添加其他初始化函数Decorator ...

def __init__(self, *args): 
    for arg in args: 
     print(arg) 

。 ..我得到以下输出:

<class '__main__.Foo'>
Goo
(<__main__.Decorator object at 0x010073B0>,)
{'__module__': '__main__'}

什么是这些参数,我应该如何在Decorator内使用它们?

回答

7

我会尝试回答“这些参数是什么”问题。此代码:

@Decorator 
class Foo: 
    pass 

相当于:

class Foo: 
    pass 
Foo = Decorator(Foo) 

这意味着Foo最终被所述Decorator类的一个实例而不是被一个类。

当您尝试将此实例用作类的基础(Goo)时,Python必须确定将用于创建新类的元类。在这种情况下,它将使用Foo.__class__,其等于Decorator。然后它将调用带有(name, bases, dict)参数的元类,并期望它返回一个新类。

这就是你如何以Decorator.__init__结束这些参数。

关于这个的更多信息可以在这里找到: http://www.python.org/download/releases/2.2.3/descrintro/#metaclasses (特别是“当一个类语句执行...”“部分)

1

您是否在类定义之后尝试将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') 

结果是s AME。

0

我有同样的问题,以下解决方案适用于我:

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__()方法的重载,以及对装饰本身作为”由装饰器返回的“包装器”,我将引用中的Wrapper设置为引号,因为实际上没有包装器,相反,装饰器类被装饰器交替并返回,使用这个方案可以从装饰类继承。最重要的是改变了装饰类的__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 
>>>