Trying to normalize behavior between a decorator WITH and without
parameters, it’s not going well…
There appears to be 2 problems with this.
- with decorator parameter’ it gets called immediately,
but without it gets called at use time. Ideally it would be
processed immediately resulting in the function being
replaced with it’s Callback instance. - I can’t figure out in this context of immediate verses late
execution, how to normalize func as the decorated func, and
cls as the Callback bases class.
Or perhaps there is a better way to do this. Thinking on the
property setters which use a prefix in the name, instead of as
parameter. I how this illustrates what I am trying to accomplish,
if unclear please comment your doubts and queries. Thank you.
The sample code is below or can be found at https://gist.github.com/ismaelharunid/0d3a5510149bc120537c1914bad73b08
# ./callback_decorator.py
from collections.abc import Callable
from types import FunctionType
#from functools import partial, wraps
class Callback(Callable):
def __call__(self, *pargs, **nargs):
print(type(self).__name__, pargs, nargs)
class CustomCallback(Callback):
pass
def callback(target_or_class, base=Callback):
"decorator for normalizing callbacks."
def a_function_that_returns_the_target():
def dummy(*pargs, **nargs):
print("dummy", pargs, nargs)
return dummy
def wrapper():
def normalize():
"""
Code to resolve the following values:
func:FunctionType The target function to decorate;
cls:type a Callback class type as the interface.
as target_or_class' contents will vary depending on whether
the decorator was called (with decorator parameters) or simply
decorating (without decorator parameters). Examples below
decorator.
"""
if isinstance(target_or_class, type):
cls = target_or_class
if not issubclass(cls, base):
raise ValueError("`cls` expects a subclass of {!r},"
" but found {!r}".format(base, cls))
func = a_function_that_returns_the_target()
elif isinstance(target_or_class, FunctionType):
func = target_or_class
cls = base
else:
raise ValueError("parameter expects a class,"
" but found {!r}"
.format(target_or_class))
return func, cls
func, cls = normalize()
name = ''.join(token for token
in (i.strip() for i
in func.__name__.title().split('_'))
if token) + cls.__name__
return type(name, (cls,), dict(__call__=func))()
return wrapper()
@callback # note, without parameters
def callback1(self, *pargs, **nargs):
print("called callback1", self, pargs, nargs)
callback1()
@callback(CustomCallback) # note, WITH parameters
def callback2(self, *pargs, **nargs):
print("called callback2", self, pargs, nargs)
callback2()