Here is a sample decorator:
def smart_divide(func):
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a,b)
return inner
@smart_divide
def divide(a,b):
return a/b
If func
is an object then how do the variables a
and b
get accessed from it?
Isn't it like trying to to do this?
def func(potato):
print(y, x)
Is there a fundamental concept I am not getting? Is what is happening here part of some pattern in Python or is it a special case situation where a
and b
know were to look because it is a generator?
Update
New example from another stack exchange answer
def my_shiny_new_decorator(a_function_to_decorate):
def the_wrapper_around_the_original_function():
print("Before the function runs")
a_function_to_decorate()
print("After the function runs")
return the_wrapper_around_the_original_function
def a_stand_alone_function():
print("I am a stand alone function, don't you dare modify me")
Generators the manual way
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
Generators the proper way
@my_shiny_new_decorator
def another_stand_alone_function():
print("Leave me alone")
According to the place where I got the new answer from the 'manual' way and the 'proper way' are the same .
I think this example may have caused me to get stuck as I was trying to extend it to when there were parameters involved.
I now realise that what I was imagining didn't make sense
I thought that the original code I posted was equivalent to this
divide = smart_divide(divide(a,b))
which if executed would look like this
def smart_divide(divide(a,b)):
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a,b)
return inner
But this would cause divide(a,b) to be executed right in the top line
in the new example 'a_stand_alone_function' did not have () on the end. Which means it was treated as an object.
So my idea of it looking like this def smart_divide(divide(a,b)):
doesn't make sense because the function won't be treated as an object anymore
This leaves me confused as to how smart_devide
get the information passed as a parameter.
No, your decorator returns inner
as new implementaion for divide
. Thus, you first call the function inner
when your program executes divide(1, 2)
for instance. Calls to divide
have always to respect the signature of inner
(and divide as in your code).
A function like
def divide(a, b): # signature
return a / b # implementation or body
consists of two parts. The signature describes the parameters, and the implementation what the function does.
Your decorator will only modify the implementation of your function as follows:
def divide(a, b): # signature remains unmodified
print("I am going to divide",a,"and",b) # implementation of inner
if b == 0:
print("Whoops! cannot divide")
return
return a / b # call to the original implementation of divide
The name and the signature of divide
remains the same. Thus, the signature of inner
matters, and not the signature of your decorator.
smart_divide
doesn't get a
and b
passed into it. It returns a function object (the inner
function), and that function gets a
and b
passed into it .
You can see what's actually happening if you try this:
def smart_divide(func):
print("I am running in smart_divide; func=", func)
def inner(a,b):
print("I am going to divide",a,"and",b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a,b)
print("I am returning from smart_divide")
return inner
print("I am running at top level before declaring divide")
@smart_divide
def divide(a,b):
return a/b
print("The name 'divide' now refers to", divide)
print("I am now going to call the divide function")
divide(1, 2)
This outputs:
I am running at top level before declaring divide I am running in smart_divide; func= <function divide at 0x108ff2bf8> I am returning from smart_divide the name 'divide' now refers to <function smart_divide.<locals>.inner at 0x10565db70> I am now going to call the divide function I am going to divide 1 and 2
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.