【问题标题】:Python Decorators & Nested Functions return statement. Proper usage with parenthesis?Python 装饰器和嵌套函数返回语句。正确使用括号?
【发布时间】:2017-12-11 22:14:01
【问题描述】:

包括/不包括 return 声明中用于装饰器(和任何嵌套函数)的内部函数的括号有什么区别?是否仅当函数返回超过 1 个变量时才需要括号?

在下面的示例中,我知道除非我使用return inner(),否则这将不起作用,但我看到其他示例在return 上不使用(),它们工作正常。

原因背后的术语会很好,因此可以帮助我完全理解。谢谢。

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner()

@stars
def func():
    print('Decorate this message.')

它最初打印我的信息,装饰。但是如果我再次调用 func(),它不会打印任何东西。

另一个工作示例,但 return inner 在这种情况下工作正常,只要我设置我的函数以支持可调用变量,在我的示例中为 msg

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner

@star
def func(msg):
    print(msg)
func("Another message to be decorated")

我可以每次调用 func('my new message') 来打印我的消息,装饰。当我不使用可调用函数时,为什么与上一个示例相比?

【问题讨论】:

  • 用另一个例子更新了我的问题,没有括号的工作“返回内部”。希望这有助于更有意义。
  • 重要的一点是def fun:... 之前的装饰器@decofun = deco(fun) 的语义糖,出现在def 的末尾之后。

标签: python python-3.x return python-decorators


【解决方案1】:

在装饰器中你不应该这样做return inner()

这意味着你正在用调用包装函数的结果替换装饰函数

您的代码将立即打印修改后的消息,甚至无需您尝试调用func()!!

**************************************************
Decorate this message.
**************************************************

但这不是你装饰函数时的意图。

您打算修改函数的行为,但仍希望必须手动调用该函数。

这就是为什么代码应该是:

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

@stars
def func():
    print('Decorate this message.')

func()
**************************************************
Decorate this message.
**************************************************

进一步解释:

当你使用装饰器语法时

@stars
def func():

您是在告诉 python 执行以下操作:

func = stars(func)

换句话说,def func,但是用调用stars(func)的结果替换函数

如果您不在代码中重复使用名称 func,您可能会发现它不那么令人困惑。例如:

def stars(func):
    def inner():
        print("*" * 50)
        func()
        print("*" * 50)
    return inner

@stars
def print_a_message():
    print('Decorate this message.')

print_a_message()
**************************************************
Decorate this message.
**************************************************

也许现在更清楚了,当我们从装饰器中执行 return inner 时,我们是在告诉 Python 替换 print_a_messageinner

【讨论】:

  • 明白。什么时候是使用带括号的return some_inner_fucntion() 的好时机?有什么简单的例子吗?
  • @tdm 基本上,从来没有(在装饰器的上下文中......在其他 python 代码中有无限的用途)
  • 去吧。完全实现stars() 基本如何构建并返回嵌套函数inner() 以便稍后调用。然而,当我使用return func() 时,我错误地立即从 inner() 返回了返回值。不是return inner 现在有意义。谢谢。
【解决方案2】:

通过调用inner函数,而不是返回函数对象,func在装饰时被调用。

stars(func) -> inner() -> func() # with some side effects

这通常不是我们想要的。该函数被修饰为稍后调用。

更重要的是,如果您的函数接受参数,这肯定行不通,因为您需要实际调用带有有效参数的修饰函数才能传递它们转至inner,然后转至func

【讨论】:

    【解决方案3】:

    您调用inner 函数而不是返回它。下面的代码包装了func 函数,而不是像上面粘贴的代码那样立即调用它。

    def stars(func):
        def inner():
            print("*" * 50)
            func()
            print("*" * 50)
        return inner
    
    @stars
    def func():
        print('Decorate this message.')
    

    【讨论】:

      【解决方案4】:

      不同之处在于,使用括号,您不会返回装饰器函数。相反,您正在返回函数的 返回值,这意味着您过早地调用了修饰函数。如果你没有括号,你的代码会正常工作,并且会返回函数对象inner

      简而言之,不要调用该函数。您需要返回实际函数本身才能使您的装饰器正常工作:

      >>> def stars(func):
              def inner():
                  print("*" * 50)
                  func()
                  print("*" * 50)
              return inner # Don't call inner, return it.
      
      >>> @stars
      def func():
          print('Decorate this message.')
      
      
      >>> func()
      **************************************************
      Decorate this message.
      **************************************************
      >>> 
      

      如果您还是调用了inner,那么当定义func() 而不是调用func() 时,您的消息就会被打印出来。

      【讨论】:

      • “相反,您正在返回函数的返回值” - 这有助于我点击。谢谢!
      猜你喜欢
      • 2015-10-09
      • 2016-09-25
      • 1970-01-01
      • 2015-06-11
      • 2018-02-07
      • 2016-05-17
      • 2020-12-04
      • 2021-03-10
      • 1970-01-01
      相关资源
      最近更新 更多