I was trying to have my class-based decorator keeping the repr()
behavior of the original wrapped function (to match the way the functools.wraps
decorator works on functions). I am using python 3.3.
First I tried functools:
import functools
class ClassBasedDecorator():
def __init__(self, fn):
self.fn = fn
functools.update_wrapper(self, fn)
def __call__(self, *args, **kwargs):
self.fn(*args, **kwargs)
@ClassBasedDecorator
def wrapped(text):
pass
But when I call repr()
on the decorated function, I get:
>>> repr(wrapped)
'<__main__.ClassBasedDecorator object at 0x2d8860b6850>'
Very well, so I tried to customize the __repr__
method of my decorator, which is supposed to be called by repr()
.
Using functools again:
class ClassBasedDecorator():
def __init__(self, fn):
self.fn = fn
functools.update_wrapper(
self, fn,
assigned=functools.WRAPPER_ASSIGNMENTS + ('__repr__',)
)
def __call__(self, *args, **kwargs):
self.fn(*args, **kwargs)
Doesn't change the output, but something interesting happens:
>>> repr(wrapped)
'<__main__.ClassBasedDecorator object at 0x2d8860b69d0>'
>>> wrapped.__repr__()
'<function wrapped at 0x2d8860a9710>'
Explicitly setting the __repr__
method of the decorator instance has the same effect.
After a little more tests I deduced repr(instance)
actually calls instance.__class__.__repr__(instance)
. Thus the overriden __repr__
method of the instance is never called.
So here are my questions:
- Why does
repr(instance)
call the instance.__class__.__repr__(instance)
instead of instance.__repr__()
? Or have I missed something else?
- How would you fully reproduce what
functools.wraps
does with function-based decorators to class-based decorators (including altering the result of repr()
calls on the decorated function)?