python中的装饰器中foo = bar(foo)和something = bar(foo)有什么区别?

时间:2017-08-26 20:25:01

标签: python python-2.7 decorator python-decorators

我读到我们可以在python中创建任何函数的引用,但我也读到了在创建装饰器时我们使用了一种称为" @"的特殊语法。 :例如:@decorator_function  此@decorator_function等于new_function=decorator_function(new_function)

所以我怀疑在我看来:

  1. anything = decorator_function(new_function)
  2. new_function=decorator_function(new_function)
  3. 两者都扮演着封闭的角色,但两者都产生了不同的输出。那么两者之间有什么大不同?

    示例代码:

    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)
    

3 个答案:

答案 0 :(得分:4)

您编写的原始something函数会对something进行递归调用,而不是a

如果您将deco(something)分配给a,则something仍然是原始函数,递归调用将调用原始函数:

  • 新函数调用原始函数
  • 原始函数查找something,找到原始函数
  • 原始函数调用原始函数...

如果您将deco(something)分配给something,则something现在是新功能,递归调用将调用新功能:

  • 新函数调用原始函数
  • 原始函数查找something,找到新函数
  • 原始函数调用新函数
  • 新函数调用原始函数...

答案 1 :(得分:1)

对于第一个,run

a = deco(something)

第二个def deco(fn): def wrapper(*args): print('called') return something(*args) # Notice here return wrapper 相同除了您的原始函数something = deco(something)现在已成为something返回的wrapper函数。

deco

>>> something <function deco.<locals>.wrapper at 0x7fbae4622f28> >>> a <function deco.<locals>.wrapper at 0x7fbae4622ea0> somethinga分配覆盖原始 something之前将其包裹起来。 Python在内部将原始something = deco(something)函数存储在包装函数中的某个位置:

something

在最后一次作业中,>>> something.__closure__[0].cell_contents <function something at 0x7fbae4622bf8> >>> a.__closure__[0].cell_contents <function something at 0x7fbae4622bf8> 变得与众不同:

something

答案 2 :(得分:0)

使用手动调用装饰器的两个作业都有效。但是其中一个(重新绑定something)替换了原始函数,因此无法再通过其原始名称来访问它。它与使用任何其他任务没有任何不同。例如:

def foo(x):
    return x + 1

a = 10

a = foo(a)

当您将foo(a)的结果分配给a时,它会将10的旧值替换为新值11。您无法再获得10

装饰器语法做同样的事情。

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

不禁止使用装饰器来创建不同名称的函数,它通常不常用(因此没有特殊的语法):

def func_3(x):
    pass

func_4 = deco(func_3) # this works, creating a new function name without hiding the old one