In Python, what is the difference between using the same decorator with and without parentheses?
For example:
Without parentheses:
@some
If you have a decorator that can be used with or without parameters, you can use the following decorator on your decorator to make it usable with or without parentheses, like this:
>>> @omittable_parentheses(allow_partial=True)
... def multiplier(multiply_by=2):
... def decorator(func):
... def multiplying_wrapper(*args, **kwargs):
... return multiply_by * func(*args, **kwargs)
... return multiplying_wrapper
... return decorator
...
>>> @multiplier
... def no_parentheses():
... return 2
...
>>> no_parentheses()
4
>>> @multiplier()
... def parentheses():
... return 2
...
>>> parentheses()
4
>>> @multiplier(3)
... def parameter():
... return 2
...
>>> parameter()
6
If allow_partial=True
is given, the resulting decorator will also work with with partial
:
>>> from functools import partial
>>> multiply_by_3 = partial(multiplier, multiply_by=3)
>>>
>>> @multiply_by_3
... def partial_no_parentheses():
... return 2
...
>>> partial_no_parentheses()
6
>>> @multiply_by_3()
... def partial_parentheses():
... return 2
...
>>> partial_parentheses()
6
Decorator code:
from functools import wraps
def omittable_parentheses(maybe_decorator=None, /, allow_partial=False):
"""A decorator for decorators that allows them to be used without parentheses"""
def decorator(func):
@wraps(decorator)
def wrapper(*args, **kwargs):
if len(args) == 1 and callable(args[0]):
if allow_partial:
return func(**kwargs)(args[0])
elif not kwargs:
return func()(args[0])
return func(*args, **kwargs)
return wrapper
if maybe_decorator is None:
return decorator
else:
return decorator(maybe_decorator)
As a bonus, this decorator decorator can be itself used with or without parentheses!