4 ms·
Decorators were easy until I tried making decorators which would work directly with parameters as well as when being invoked as individual instances with parame
by Sami_Lehtinen 11y ago
Decorators were easy until I tried making decorators which would work directly with parameters as well as when being invoked as individual instances with parameters. Then things got quite messy and it was hard to understand why it works as it does.
- zardeh 11y agoconsider the example @decorator_without_args def function(): pass this is equivalent to function = decorator_without_args(function) now consider the other case, where the decorator takes in some args: @dec_with_args("hello", "world") def func(): pass this is equivalent to function = decorator_with_args("hello", "world")(function) Or in other words, the expression after @ needs to evaluate to a Callable which is then called on the function you are decorating, so with @a_decorator, you call a_decorator on your function. When you use @with_args(1, 2, 3), you are calling the function "with_args" and then the result of that function is your decorator. So an example of this working is like so: debug_list = [] other_list = [] def dynamic_debug_decorator(output_list=debug_list): # dynamic debug decorator should return a decorator function # realistically, ddd is a decorator factory, not a decorator def debug_decorator(function): # so this is our real decorator def decorated_function(*args, **kwargs): # and this is the new function we return output_list.append(function) # because silly example return function(*args, **kwargs) return decorated_function return debug_decorator so now using that decorator: @dynamic_debug_decorator def function(): pass this fails, because dynamic debug decorator takes a list, but is now receiving a function. Instead we need to call it like so: @dynamic_debug_decorator def function(): pass this works, using the default values.
- RussianCow 11y agoI think you meant to call `dynamic_debug_decorator` in your last example. Right now the two examples you show are exactly the same (both incorrect). It should be: @dynamic_debug_decorator() def function(): pass
- zardeh 11y agoyou are exactly correct.
- knome 11y agoIf you really wanted to make the parameters optional, you could have your decorator accept ( callable = None, ^^kwargs ) and then check if `callable` is a function object ( or class / callable / whatever ) or None. If it is a direct application of the decorator then directly decorate with defaults, otherwise return a wrapping function with the given parameters to await the function as need be. annoyed edit: replace ^ with asterisk, which I can't get HN to print even escaping them with backslashes. thanks bad syntax formatting code