【问题标题】:what is difference between foo=bar(foo) and something=bar(foo) in decorator in python?python 装饰器中的 foo=bar(foo) 和 something=bar(foo) 有什么区别?
【发布时间】:2018-02-04 13:34:31
【问题描述】:

我读到我们可以在 python 中创建任何函数的引用,但我也读到在创建装饰器时我们使用称为“@”的特殊语法:例如:@decorator_function 而这个@decorator_function 等于new_function=decorator_function(new_function)

所以我的怀疑是在我看来:

  1. anything = decorator_function(new_function)
  2. new_function=decorator_function(new_function)

两者都扮演着闭包的角色,但都导致不同的输出。那么两者有什么大的区别呢?

示例代码:

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)

【问题讨论】:

    标签: python python-2.7 decorator python-decorators


    【解决方案1】:

    您编写的原始@​​987654321@ 函数递归调用something,而不是a

    如果将deco(something)赋值给a,那么something仍然是原函数,递归调用会调用原函数:

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

    如果将deco(something)分配给something,那么something现在就是新函数,递归调用会调用新函数:

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

    【讨论】:

    • 第二段中的新功能是什么意思?
    • @Elanaunderhill:由deco创建并返回的函数。
    • 举例说明比较好?
    • @user2357112 在第二个 p 中,您正在使用调用 something = deco(something) 覆盖函数 something。初始的something 函数将永远不会被再次调用。
    • @DanielF:会的,因为新函数调用了原来的函数。
    【解决方案2】:

    对于第一个,a = deco(something)

    def deco(fn):
        def wrapper(*args):
            print('called') 
            return something(*args)      # Notice here
    return wrapper 
    

    第二个,something = deco(something) 和原来的函数something 一样除了现在变成了deco 返回的wrapper 函数。

    >>> something
    <function deco.<locals>.wrapper at 0x7fbae4622f28>
    >>> a
    <function deco.<locals>.wrapper at 0x7fbae4622ea0>
    

    somethinga 在被something = deco(something) 赋值覆盖之前包装原始 something。 Python 在内部将原始 something 函数存储在包装函数的某个位置:

    >>> something.__closure__[0].cell_contents
    <function something at 0x7fbae4622bf8>
    
    >>> a.__closure__[0].cell_contents
    <function something at 0x7fbae4622bf8>
    

    在上一个作业中something 变得不一样了:

    >>> something
    <function deco.<locals>.wrapper at 0x7fbae4622f28>
    

    【讨论】:

      【解决方案3】:

      您的两个作业都使用手动调用装饰器工作。但是其中一个(重新绑定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
      

      【讨论】:

        猜你喜欢
        • 2017-06-23
        • 1970-01-01
        • 1970-01-01
        • 2015-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-04
        相关资源
        最近更新 更多