2011-09-19 126 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 
>>>