Question about the wrapper in a decorator [duplicate] - python

This question already has answers here:
How do I make function decorators and chain them together?
(20 answers)
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 11 months ago.
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!

Related

Why does an outer function call an inner function in python, without explicitly calling it? [duplicate]

This question already has answers here:
Python decorator? - can someone please explain this? [duplicate]
(7 answers)
How do I make function decorators and chain them together?
(20 answers)
Closed 3 months ago.
This post was edited and submitted for review 3 months ago and failed to reopen the post:
Original close reason(s) were not resolved
NOTE: This question is not directly related to decorators, but rather the concept of them.
It is NOT related to these 2 questions:
What is decorator with "#" above a function in Python? [duplicate] (7 answers)
How do I make function decorators and chain them together? (19 answers)
MY QUESTION:
I'm currently experimenting with inner functions to get a good grasp of python decorators.
With this code below, I am able to successfully print "sup" through the wrapper function, even though I didnt explicitly call it.
def my_decorator(test):
def wrapper():
print(test)
return wrapper
hello = my_decorator("sup")
hello()
This however, doesnt work if I do any of the following
remove return wrapper
directly call my_decorator("sup") without passing it into the hello function
correspondingly, I have 2 questions:
does return wrapper automatically call the wrapper function?
What's the difference between using a reference function like hello, and directly calling the my_decorator function?

Understanding how does a decorator really work [duplicate]

This question already has answers here:
How do I make function decorators and chain them together?
(20 answers)
Closed 4 years ago.
I'm starting studying decorators and I already hit an obstacle. First here is my code.
def deco (f):
def coucou():
print("this is function{}".format(f))
return f()
return coucou
#deco
def salut():
print("salut")
def hi():
return salut()
I will try to explain my problem as well as I can with my bad English. If I understand it this is how things should happen: I execute my hi() function which returns salut() and because salut is modified by the decorator coucou will be executed and coucou returns ....... salut(), what i mean is that I expect an infinite loop but that doesn't happen and I don't understand why. Can anyone explain practically how decorators work?
The f in coucou is the undecorated (original) version of salut.

What is the difference in *args, **kwargs vs calling with tuple and dict? [duplicate]

This question already has answers here:
What does ** (double star/asterisk) and * (star/asterisk) do for parameters?
(25 answers)
Closed 6 years ago.
This is a basic question. Is there a difference in doing
def foo(*args, **kwargs):
"""standard function that accepts variable length."""
# do something
foo(v1...vn, nv1=nv1...nvn=nvn)
def foo(arg, kwargs):
"""convention, call with tuple and dict."""
# do something
mytuple = (v1, ..vn)
mydict = {nv1=nv1, ...nvn=nvn}
foo(mytuple, mydict)
I could do the same thing with both, except that the later has a weird convention of creating a tuple and dictionary. But basically is there a difference? I can solve the same computational problem of handling infinite things because dict and tuple can take care of that for me anyway?
Is this more of an idiomatic part of Python i.e a good Syntactic Sugar for things that you do anyway? I.e function is going to handle this for you!
PS: Not sure of so many downvotes though I agree this is a copy of Why use packed *args/**kwargs instead of passing list/dict? and probably it should be corrected in the duplicate information. And that question has recieved upvotes. So am I being downvotes for not being able to find that?
args and kwargs are just names.
What really matters here is the * and **.
In your second example you can only call the function with 2 arguments, against the first example where you can call the function with basically infinite arguments.

Understanding Function Closures [duplicate]

This question already has answers here:
Why aren't python nested functions called closures?
(10 answers)
Closed 8 years ago.
I'm struggling to understand Function closures properly. For example in the code below I am unclear as to how the function knows that in the statement times3(2) that x=2? Also, after reading documentations I still can't fully understand the purpose of closures.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
times3 = make_multiplier_of(3)
times3(2) #How does the function know that x=2 here?
Thanks a lot
When you are calling make_multiplier_of(3), the function is returning multiplier such that
def multiplier(x):
return x*3
So times3 = make_multipiler(3) is assigning this particular multiplier function to times3. The same way that when you are doing myLength=len, myLength is the len function and you can call myLength("foo")
times3 is thus this multiplier function. So when you times3(2), you are doing (this particular) multiplier(2)

How do return values work? [duplicate]

This question already has answers here:
I need help wrapping my head around the return statement with Python and its role in this recursive statement
(2 answers)
Closed 8 years ago.
def fudz(n):
if n <= 2:
return 1
print("nom" * n)
return fudz(n-1) + fudz(n//2)
result = fudz(4)
Can someone give me a step by step of this function?
This is a recursive function, which means it calls an instance of itself on a simplified instance of the problem until it gets to a base case for which it already knows the answer. Remember that any call to a function occurs in its own stack frame, so it's going to have its own value for n.
You can walk through it yourself. First, think about what happens when n==2. Then think about n==3, and increase n until it makes sense to you.

Categories