I read about we can create reference of any function in python but i also read that while creating a decorator we use a special syntax called "@" : ex: @decorator_function and this @decorator_function
is equal to new_function=decorator_function(new_function)
so my doubt is in my view both :
anything = decorator_function(new_function)
new_function=decorator_function(new_function)
both are playing the role of closure but both result different output. so what is big difference between both of them?
example code :
def deco(fn):
def wrapper(*args):
print('called')
return fn(*args)
return wrapper
def something(x):
if x == 0:
print('first')
something(x+1)
else:
print('hello')
print('new name')
a = deco(something)
a(0)
print('\nreassigning to the same name')
something = deco(something)
something(0)
The original something
function you wrote makes a recursive call to something
, not a
.
If you assign deco(something)
to a
, then something
is still the original function, and the recursive call will call the original function:
something
, finds original function If you assign deco(something)
to something
, then something
is now the new function, and the recursive call will call the new function:
something
, finds new function For the first one, a = deco(something)
def deco(fn):
def wrapper(*args):
print('called')
return something(*args) # Notice here
return wrapper
The second one, something = deco(something)
is just the same except your original function something
now has become the wrapper
function that deco
returned.
>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
>>> a
<function deco.<locals>.wrapper at 0x7fbae4622ea0>
Both something
and a
wrap the original something
before it was overridden by something = deco(something)
assignment. Python internally stored the original something
function somewhere in the wrapper functions:
>>> something.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>
>>> a.__closure__[0].cell_contents
<function something at 0x7fbae4622bf8>
In the last assignment something
has become something different:
>>> something
<function deco.<locals>.wrapper at 0x7fbae4622f28>
Both of your assignments using manual calls to the decorator work. But one of them (the one that rebinds something
) replaces the original function so that it can't be reached by its original name any more. It's not any different than using any other assignment. For instance:
def foo(x):
return x + 1
a = 10
a = foo(a)
When you assign the result of foo(a)
to a
, it replaces the old value of 10
with a new value 11
. You can't get the 10
any more.
Decorator syntax does the same thing.
def deco(fn):
def wrapper(*args):
print('called')
return fn(*args)
return wrapper
def func_1(x):
pass
func_1 = deco(func_1) # replace the old func_1 with a decorated version
@deco # the @ syntax does the same thing!
def func_2(x):
pass
It's not forbidden to use a decorator to create a differently named function, it's just not normally as useful (and so there's no special syntax for it):
def func_3(x):
pass
func_4 = deco(func_3) # this works, creating a new function name without hiding the old one
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.