Reputation: 620
I was working on making a wrapper object that would take an instance of an arbitrary class and then automatically wrap all of its own magic methods to simply use the magic method (and value) of the wrapped object. For some reason, this doesn't work:
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
I thought maybe the partial wasn't working properly with the distinction between the type's method and an instance method, but when I directly call my wrapper's magic add, it works properly. (This is tested in CPython 3.3)
Upvotes: 1
Views: 1027
Reputation: 1124010
Special methods are always looked up on the type of the instance (here the class object), not on the instance. Otherwise a __repr__
on a class would be used when you tried to print the representation of the class itself; type(class).__repr__(class)
would use the correct magic method, while class.__repr__()
would raise an exception because self
was not provided.
You'll need to implement these special methods directly on the wrapper, propagating any exceptions that might be raised when called on the wrapped object.
Upvotes: 2