Reputation: 75
I want to be able to stack a decorator on singledispatchmethod. If that is not possible, at least on the individual registered functions.
There is probably a simple and elegant solution. I have not found it... yet.
Extending the sample from the official documentation:
from functools import singledispatchmethod
def eavesdrop(method): # my beautiful decoration
def wrapper(self, arg):
print(f"Negating {arg}")
return method(self, arg)
return wrapper
def workaround(method, arg): # no beauty, no decoration
print(f"Negating {arg}")
return method(arg)
class Negator:
# @eavesdrop # AttributeError: 'function' object has no attribute 'register'
@singledispatchmethod
# @eavesdrop # does nothing
def neg(self, arg):
raise NotImplementedError("Cannot negate a")
# @eavesdrop # does nothing
@neg.register
# @eavesdrop # TypeError: Invalid first argument to `register()`: <function double...
def _(self, arg: int):
return -arg
@neg.register
def _(self, arg: bool):
return not arg
@neg.register
def _(self, arg: float):
return workaround(lambda v: -v, arg) # use only in case of despair
I hope to find the solution here. Thanks!
Upvotes: 1
Views: 284
Reputation: 110561
It is just a matter of preserving the properties of the decorated function when wrapping it with your decorator. In this case, you have to carry over the annotations of the original method, so that the machinery of singledispatchmethod
can see it.
The simpler way to do it is functools.wraps
:
from functools import singledispatchmethod, wraps
def eavesdrop(method): # my beautiful decoration
@wraps(method)
def wrapper(self, arg):
print(f"Negating {arg}")
return method(self, arg)
return wrapper
class Negator:
@singledispatchmethod
@eavesdrop
def neg(self, arg):
raise NotImplementedError("Cannot negate a")
@neg.register
@eavesdrop
def _(self, arg: int):
return -arg
@neg.register
@eavesdrop
def _(self, arg: bool):
return not arg
@neg.register
@eavesdrop
def _(self, arg: float):
return workaround(lambda v: -v, arg) # use o
Upvotes: 1