2012-10-21 17 views
0

我想創建一個包裝類,其行爲與包裝對象的行爲完全相同(只有一些特定的例外情況)。我現在遇到的問題是內置函數。我如何將內置函數重定向到包裝對象?將內置函數重定向到包裝類

class Wrapper: 
    def __init__(self, wrapped): 
     object.__setattr__(self, '_wrapped', wrapped) 
    def __getattr__(self, name): 
     return getattr(object.__getattribute__(self, '_wrapped'), name) 

class Foo: 
    def __init__(self, val): 
     self.val = val 
    def __abs__(self): 
     return abs(self.val) 

foo = Wrapper(Foo(-1)) 
print(foo.val) # Okay 
print(abs(foo)) # TypeError: bad operand type for abs(): 'Wrapper' 
+0

'包裝器'應該定義'__abs__'。最簡單的可能是從'Foo'繼承。這可以通過元類動態完成。 –

+0

如果你想跟蹤對象的變化,你只需要打包mutables。數字不可變,所以你不需要包裝這些數字。 –

+0

@MartijnPieters我知道,這只是一個玩具的例子。 –

回答

3

您可以動態創建一個新的類,它是既WrapperFoo的子類,所以你有所需的所有特性:

class Wrapper: 
    def __new__(self, wrapped): 
     cls = type(wrapped) 
     new_type = type(cls.__name__ + '_wrapped', (Wrapper, cls), {}) 
     return object.__new__(new_type) 

    def __init__(self, wrapped): 
     self._wrapped = wrapped 
    def __getattr__(self, name): 
     return getattr(self._wrapped, name) 

所以現在你可以這樣做:

>>> foo = Wrapper(Foo(-1)) 
>>> abs(foo) 
1 
>>> type(foo) 
<class '__main__.Foo_wrapped'> 

PS:

  • 您在__init____getattr__函數中不需要object.__getattr__(或__setattr__)以獲取和設置此屬性。
  • 您可能想要緩存此操作以避免在每個新對象上創建一個新類。
+0

我想父母的順序很重要。 'Wrapped'應該首先使'__getattr__'方法具有更高的優先級。 –

+0

@PaulManta是的。那就是'(Wrapper,Cls)'元組所做的。它將'Wrapper'設置爲第一個父項 – JBernardo