Using python decorator with or without parentheses

后端 未结 4 1776
心在旅途
心在旅途 2021-02-01 01:04

In Python, what is the difference between using the same decorator with and without parentheses?

For example:

Without parentheses:

@some         


        
4条回答
  •  深忆病人
    2021-02-01 01:47

    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!

提交回复
热议问题