How to create a Python decorator that can be used either with or without parameters?

前端 未结 13 1641
死守一世寂寞
死守一世寂寞 2020-11-30 21:26

I\'d like to create a Python decorator that can be used either with parameters:

@redirect_output(\"somewhere.log\")
def foo():
    ....

or

13条回答
  •  时光说笑
    2020-11-30 21:32

    I know this is an old question, but I really don't like any of the techniques proposed so I wanted to add another method. I saw that django uses a really clean method in their login_required decorator in django.contrib.auth.decorators. As you can see in the decorator's docs, it can be used alone as @login_required or with arguments, @login_required(redirect_field_name='my_redirect_field').

    The way they do it is quite simple. They add a kwarg (function=None) before their decorator arguments. If the decorator is used alone, function will be the actual function it is decorating, whereas if it is called with arguments, function will be None.

    Example:

    from functools import wraps
    
    def custom_decorator(function=None, some_arg=None, some_other_arg=None):
        def actual_decorator(f):
            @wraps(f)
            def wrapper(*args, **kwargs):
                # Do stuff with args here...
                if some_arg:
                    print(some_arg)
                if some_other_arg:
                    print(some_other_arg)
                return f(*args, **kwargs)
            return wrapper
        if function:
            return actual_decorator(function)
        return actual_decorator
    

    @custom_decorator
    def test1():
        print('test1')
    
    >>> test1()
    test1
    

    @custom_decorator(some_arg='hello')
    def test2():
        print('test2')
    
    >>> test2()
    hello
    test2
    

    @custom_decorator(some_arg='hello', some_other_arg='world')
    def test3():
        print('test3')
    
    >>> test3()
    hello
    world
    test3
    

    I find this approach that django uses to be more elegant and easier to understand than any of the other techniques proposed here.

提交回复
热议问题