0

I learne d (or tried to learn) decorators recently with python. I've coded this, but I actually don't fully understand how it actually works...

The code:

def logging_decorator(fn):
    def wrapper(*args, **kwargs):
        print(f"You called {fn.__name__}{args}")
        result = fn(args[0], args[1], args[2])
        print(f"It returned: {result}")
    return wrapper


@logging_decorator
def a_function(a, b, c):
    return a * b * c


a_function(1, 2, 3)

My question: I dont understand how in the wrapper the args become the inputs (a,b,c) of the function "a_function". it looks like magic to me I don't see how the inputs of the wrapper became those of the function "a_function".

My research: I've watched 3 videos on the subject but none of them really focuses on that aspect of the problem. I've asked on other forums but still didn't get a satisfactory answer. I guess people just assume it's obvious for them it should be to others as well, but as far as I'm concerned it is not! I've had no problem using decorators in the past and understanding until I've tried to add inputs in the wrapper (trying to get the parameters of the function that we fetch to the decorator).

you're answer will be highly appreciated and I thank you in advance!

  • 2
    After the decorator is applied to your function, `a_function` *is* the `wrapper` function. So calling `a_function(1, 2, 3)`, you're really calling `wrapper(1, 2, 3)`. Inside `wrapper`, `fn` is the original function you decorated. Is that clear? From there it's just argument unpacking with `*`. Can you focus more on what's unclear to you? – deceze Mar 23 '22 at 07:55
  • so actually what is unclear is why the wrapper becomes a_function? Can you explain why and how? Actually how is more important obviously, but both why and how are equivalent in this case – younes alaoui Mar 23 '22 at 08:33
  • Because the `@decorator def f(): ...` syntax is equivalent to `def f(): ...` `f = decorator(f)`. That's really all it does. Just think that through and it's somewhat obvious. – deceze Mar 23 '22 at 08:35
  • I mean I get that I just don't understand by which magic the wrapper gets the args. could you explain the path of that those args take from beginning to end? I know that i set the args in my original function then my original function gets inputted inside the decorator along with it's parameters obv. But from there I don't see what path the parameters of the original function that got inputted in the decorator take to reach the args of the wrapper function inside the decorator... – younes alaoui Mar 23 '22 at 09:44
  • and also, thank you for how quick you answer my questions I cannot do the same since I'm working at the same time... – younes alaoui Mar 23 '22 at 09:44
  • `a_function(1, 2, 3)` *calls* `wrapper(1, 2, 3)`. You're directly calling the `wrapper` function, passing it arguments. See the above linked duplicate about `*args`…?! – deceze Mar 23 '22 at 09:45
  • how does a_function(1, 2, 3) calls wrapper(1, 2, 3). how am I directly calling the wrapper function and passing it arguments when all I do is f=decorator(f) and not f=wrapper(f)? – younes alaoui Mar 27 '22 at 11:15
  • 1
    `decorator(...)` *returns* `wrapper`, and you assign it to `f`. – deceze Mar 27 '22 at 18:02

0 Answers0