Parameter transfer problem of python decorator

problem description

I wrote a decorator with parameters, and now I need the decorator to use different parameters according to different conditions.

the environmental background of the problems and what methods you have tried

I wrote a decorator with parameters, and now I need the decorator to use different parameters according to different conditions.
use a for loop to pass impassable parameters into the decorator (which can be used in this case):

from functools import wraps


def log(a, b, c):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print("hello", str(a), str(b), str(c), func.__name__)
            func(*args, **kwargs)
            print("goodbye", str(a), str(b), str(c), func.__name__)
        return wrapper
    return decorator


a_l, b_l, c_l = [1, 2, 3], [4, 5, 6], [7, 8, 9]
l = list(range(5))

for i, j, k in zip(a_l, b_l, c_l):
    @log(i, j, k)
    def f():
        print("ok")
    f()

but now suppose my decorator has a lot of parameters, and there are many functions inside the for loop. I don"t want every decorator to write so many parameters, so I want to pass the parameters to the decorator first, but the error is as follows:

from functools import wraps


def log(a, b, c):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print("hello", str(a), str(b), str(c), func.__name__)
            func(*args, **kwargs)
            print("goodbye", str(a), str(b), str(c), func.__name__)
        return wrapper
    return decorator


a_l, b_l, c_l = [1, 2, 3], [4, 5, 6], [7, 8, 9]
l = list(range(5))

for i, j, k in zip(a_l, b_l, c_l):
    log = log(i, j, k)
    @log
    def f():
        print("ok")
    f()
    
-sharp
hello 1 4 7 f
ok
goodbye 1 4 7 f
Traceback (most recent call last):
  File "D:\test\ttt.py", line 22, in <module>
    log = log(i, j, k)
TypeError: decorator() takes 1 positional argument but 3 were given

you can see that the strange thing is that the first loop can be used with output, but when it comes to the second for loop, there is an error in passing parameters in the decorator. I don"t know why. Could you tell me what went wrong? Thank you!

what"s even weirder is that I can use a different function alias. The code is as follows:

from functools import wraps


def log(a, b, c):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print("hello", str(a), str(b), str(c), func.__name__)
            func(*args, **kwargs)
            print("goodbye", str(a), str(b), str(c), func.__name__)
        return wrapper
    return decorator


a_l, b_l, c_l = [1, 2, 3], [4, 5, 6], [7, 8, 9]
l = list(range(5))

for i, j, k in zip(a_l, b_l, c_l):
    lg = log(i, j, k)   -sharp loglg

    @lg
    def f():
        print("ok")
    f()

Please explain why? Thank you!

Apr.11,2021

"decorator with parameters" is not an accurate description. @ desc (arg) is better understood as the function desc is called, which returns a decorator. And you already know how to deal with it, and you just want to know why. This makes sense at one point.

first understand a function that allows re-assignment

def f():
    pass
f = 1
print(f)    -sharp 1   

then you have a good understanding of the decorator:

@log(i, j, k)
    def f():

-sharp 
tmp = log(i,j,k)
@tmp
def f():
The reason for this is that you reassign log to become a decorator rather than a function that returns the decorator. Well, the reason is that simple.

Menu