简体   繁体   中英

what is difference between foo=bar(foo) and something=bar(foo) in decorator in python?

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 :

  1. anything = decorator_function(new_function)
  2. 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:

  • new function calls original function
  • original function looks up something , finds original function
  • original function calls 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:

  • new function calls original function
  • original function looks up something , finds new function
  • original function calls new function
  • new function calls original 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM