python - 装饰器,不带括号调用函数?

标签 python python-3.x function decorator python-decorators

我正在借助一些在线教程自学编码。我遇到过“装饰者”,我似乎能理解它是如何工作的,但有些事情困扰着我。这是给出的代码:

def decor(func):
    def wrap():
        print("-----------")
        func()
        print("-----------")
    return wrap

def print_text():
    print("Hello World")

decorated = decor(print_text)
decorated()

output:
-----------
Hello World
-----------

我想了解的是:

  • 为什么必须调用“return wrap”而不是“return wrap()”?而如果不这样做,您将收到“TypeError:'NoneType' 对象不可调用。

  • 当我给装饰变量赋值时。为什么我还必须使用“print_text”而不是“print_text()”,而如果我这样做,它会引发相同的 TypeError?

  • 当我使用变量“decorated”时。为什么我必须像函数一样调用它(在末尾添加 () )。当我用“decorated”或“print(decorated)”来调用它时,它说的是完全不同的意思吗?

抱歉提出愚蠢的问题。但我才刚刚开始,所以请多多包涵。另外,请让您的回答对初学者友好。谢谢

最佳答案

在 Python 中,几乎一切都是对象。函数也是对象。您可以通过他们的名字来引用他们:

>>> def print_text():
...     print("Hello World")
...
>>> print_text   # **no** call here, this is just referencing the object
<function print_text at 0x10e3f1c80>
>>> print_text() # With a call, so now we *run* the function
Hello World

在名称中添加 () 告诉 Python 调用该函数,这导致它实际执行函数体,没有调用,它只是向您显示名称引用的内容。

您也可以将函数对象分配给其他名称。仍然可以调用那些其他名称,调用函数:

>>> other_name = print_text
>>> other_name
<function print_text at 0x10e3f1c80>
>>> other_name()
Hello World

所以 other_name 只是对同一对象的另一个引用,添加 ()(一个调用表达式)会导致函数对象被执行。 print_text()other_name() 做完全相同的事情,在函数内运行代码。

这就是 decor() 中的名称 func 所指的;它是对同一个函数对象的引用。你用 decor(print_text) 传入了它。只有稍后,在 wrapper() 中,表达式 func() 调用该函数对象。如果您改为传入 print_text(),则会传入函数返回的 None 对象,并且无法调用 None:

>>> return_value = print_text()
Hello World
>>> return_value is None
True
>>> return_value()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

接下来,return wrapper 将新创建的wrapper 函数对象返回给调用者。如果您执行了return wrapper(),您将返回函数的结果,而不是函数对象本身。

装饰器的全部意义在于用一个新对象替换原来的函数对象,这个新对象做额外的事情,这就是为什么装饰器返回那个替换对象(在你的例子中 wrapper),这样在将来当你调用 decorated() 时,你会调用包装函数在调用原始函数之前和之后做一些额外的事情(通过 func 名称,它引用 print_text( )).

decor(some_function) 所做的是返回一个函数对象,它会打印一些东西,调用传入的函数对象,然后打印一些东西别的。然后可以使用该新函数对象替换旧函数对象。

关于python - 装饰器,不带括号调用函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44027863/

相关文章:

javascript - 将多个变量传递给 Javascript 函数

python - 无法将变量传递给函数

python - numpy fromstring 空字符串分隔符

python - 如何获取我的python3.4中的unicode版本?

python - 用迭代器创建列表会产生意想不到的结果

python - DQN 在不同计算机上的行为不同

python - 如何处理基于 git 的 wiki 中的 merge/冲突?

python - 反转元组和反转列表有什么区别?

python - 评估所有列后删除 pandas 数据框中的行

python - if 语句循环内短路