2014-02-24 80 views
1

我正在做一個包裝對象,將採取任意類的實例,然後自動包裝所有的它自己的魔術方法簡單地使用包裝對象的魔術方法(和值)。出於某種原因,這不起作用:爲什麼我不能忽略這種魔法?

class Wrapper: 
    def __init__(self, wrapped): 
     self.wrapped = wrapped 
     for method in filter(lambda x: x.startswith("__") and (x not in 
     ["__init__", "__new__", "__class__", "__metaclass__"]), 
     dir(wrapped)): 
      if hasattr(getattr(wrapped, method), "__call__"): 
       new_func = functools.partial(getattr(type(wrapped), method), self.wrapped) 
       setattr(self, method, new_func) 


t = Wrapper(7) 
t + 8 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    TypeError: unsupported operand type(s) for +: 'Wrapper' and 'int' 

class Tester: 
    def __init__(self): 
     self.v = 5 
    def __add__(self, other): 
     return self.v + other 

y = Tester() 
y + 7 
12 
t = Wrapper(y) 
t + 9 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'Wrapper' and 'int' 

9 + t 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unsupported operand type(s) for +: 'int' and 'Wrapper' 

t.__add__ 
functools.partial(<function Tester.__add__ at 0x7fbec6372170>, <__main__.Tester object at 0x7fbec6392990>) 

t.__add__(7) 
12 

我想,也許部分沒有與該類型的方法和實例方法之間的區別正常工作,但是當我直接打電話給我的包裝的魔法加,它正常工作。 (這在CPython的3.3測試)

+2

你不能設置情況下的特殊方法,他們總是擡頭的類型。 –

+0

嗯。你是對的。我嘗試了一個類似的例子,除非我直接調用魔術方法,否則cpython會完全忽略它。你知道這是否在語言參考的某個地方嗎? (這是設計決定還是實現細節?)這個約束是否適用於所有實現? – marky1991

+0

看到我的答案,這是一個設計決定。 –

回答

2

特殊方法是always looked up on the type of the instance(這裏類對象),而不是在該實例。否則,當您嘗試打印類的表示時,將使用類上的__repr__; type(class).__repr__(class)將使用正確的魔術方法,而class.__repr__()會引發異常,因爲未提供self

你需要直接實現對包裝這些特殊方法,傳播包裝的對象上調用時可能提出的任何異常。

+0

嗯。那是個很好的觀點。我在想,這是出於性能方面的工作要做,但你說的很對,這樣做,否則有邏輯問題。謝謝! – marky1991