Decorators with parameters?

前端 未结 13 1399
我在风中等你
我在风中等你 2020-11-21 22:58

I have a problem with the transfer of variable \'insurance_mode\' by the decorator. I would do it by the following decorator statement:

@execute_complete_rese         


        
相关标签:
13条回答
  • 2020-11-21 23:14

    Writing a decorator that works with and without parameter is a challenge because Python expects completely different behavior in these two cases! Many answers have tried to work around this and below is an improvement of answer by @norok2. Specifically, this variation eliminates the use of locals().

    Following the same example as given by @norok2:

    import functools
    
    def multiplying(f_py=None, factor=1):
        assert callable(f_py) or f_py is None
        def _decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                return factor * func(*args, **kwargs)
            return wrapper
        return _decorator(f_py) if callable(f_py) else _decorator
    
    
    @multiplying
    def summing(x): return sum(x)
    
    print(summing(range(10)))
    # 45
    
    
    @multiplying()
    def summing(x): return sum(x)
    
    print(summing(range(10)))
    # 45
    
    
    @multiplying(factor=10)
    def summing(x): return sum(x)
    
    print(summing(range(10)))
    # 450
    

    Play with this code.

    The catch is that the user must supply key,value pairs of parameters instead of positional parameters and the first parameter is reserved.

    0 讨论(0)
  • 2020-11-21 23:15

    Here is a slightly modified version of t.dubrownik's answer. Why?

    1. As a general template, you should return the return value from the original function.
    2. This changes the name of the function, which could affect other decorators / code.

    So use @functools.wraps():

    from functools import wraps
    
    def decorator(argument):
        def real_decorator(function):
            @wraps(function)
            def wrapper(*args, **kwargs):
                funny_stuff()
                something_with_argument(argument)
                retval = function(*args, **kwargs)
                more_funny_stuff()
                return retval
            return wrapper
        return real_decorator
    
    0 讨论(0)
  • 2020-11-21 23:15
    def decorator(argument):
        def real_decorator(function):
            def wrapper(*args):
                for arg in args:
                    assert type(arg)==int,f'{arg} is not an interger'
                result = function(*args)
                result = result*argument
                return result
            return wrapper
        return real_decorator
    

    Usage of the decorator

    @decorator(2)
    def adder(*args):
        sum=0
        for i in args:
            sum+=i
        return sum
    

    Then the

    adder(2,3)
    

    produces

    10
    

    but

    adder('hi',3)
    

    produces

    ---------------------------------------------------------------------------
    AssertionError                            Traceback (most recent call last)
    <ipython-input-143-242a8feb1cc4> in <module>
    ----> 1 adder('hi',3)
    
    <ipython-input-140-d3420c248ebd> in wrapper(*args)
          3         def wrapper(*args):
          4             for arg in args:
    ----> 5                 assert type(arg)==int,f'{arg} is not an interger'
          6             result = function(*args)
          7             result = result*argument
    
    AssertionError: hi is not an interger
    
    0 讨论(0)
  • 2020-11-21 23:16

    define this "decoratorize function" to generate customized decorator function:

    def decoratorize(FUN, **kw):
        def foo(*args, **kws):
            return FUN(*args, **kws, **kw)
        return foo
    

    use it this way:

        @decoratorize(FUN, arg1 = , arg2 = , ...)
        def bar(...):
            ...
    
    0 讨论(0)
  • 2020-11-21 23:17

    This is a template for a function decorator that does not require () if no parameters are to be given:

    import functools
    
    
    def decorator(x_or_func=None, *decorator_args, **decorator_kws):
        def _decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kws):
                if 'x_or_func' not in locals() \
                        or callable(x_or_func) \
                        or x_or_func is None:
                    x = ...  # <-- default `x` value
                else:
                    x = x_or_func
                return func(*args, **kws)
    
            return wrapper
    
        return _decorator(x_or_func) if callable(x_or_func) else _decorator
    

    an example of this is given below:

    def multiplying(factor_or_func=None):
        def _decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                if 'factor_or_func' not in locals() \
                        or callable(factor_or_func) \
                        or factor_or_func is None:
                    factor = 1
                else:
                    factor = factor_or_func
                return factor * func(*args, **kwargs)
            return wrapper
        return _decorator(factor_or_func) if callable(factor_or_func) else _decorator
    
    
    @multiplying
    def summing(x): return sum(x)
    
    print(summing(range(10)))
    # 45
    
    
    @multiplying()
    def summing(x): return sum(x)
    
    print(summing(range(10)))
    # 45
    
    
    @multiplying(10)
    def summing(x): return sum(x)
    
    print(summing(range(10)))
    # 450
    
    0 讨论(0)
  • 2020-11-21 23:21

    Great answers above. This one also illustrates @wraps, which takes the doc string and function name from the original function and applies it to the new wrapped version:

    from functools import wraps
    
    def decorator_func_with_args(arg1, arg2):
        def decorator(f):
            @wraps(f)
            def wrapper(*args, **kwargs):
                print("Before orginal function with decorator args:", arg1, arg2)
                result = f(*args, **kwargs)
                print("Ran after the orginal function")
                return result
            return wrapper
        return decorator
    
    @decorator_func_with_args("foo", "bar")
    def hello(name):
        """A function which prints a greeting to the name provided.
        """
        print('hello ', name)
        return 42
    
    print("Starting script..")
    x = hello('Bob')
    print("The value of x is:", x)
    print("The wrapped functions docstring is:", hello.__doc__)
    print("The wrapped functions name is:", hello.__name__)
    

    Prints:

    Starting script..
    Before orginal function with decorator args: foo bar
    hello  Bob
    Ran after the orginal function
    The value of x is: 42
    The wrapped functions docstring is: A function which prints a greeting to the name provided.
    The wrapped functions name is: hello
    
    0 讨论(0)
提交回复
热议问题