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