如果我创建一个如下所示的装饰器:
def my_decorator(some_fun):
def wrapper():
print("before some_fun() is called.")
some_fun()
print("after some_fun() is called.")
return wrapper
@my_decorator
def just_some_fun():
print("Wheee!")
另一个装饰器可以定义为:
def my_decorator(some_fun):
print("before some_fun() is called.")
some_fun()
print("after some_fun() is called.")
@my_decorator
def just_some_fun():
print("some fun")
两个装饰器的工作方式相同。在装饰器中使用“包装器”功能有什么好处?我没明白目的。
拥有包装函数的目的是函数装饰器接收要装饰的函数对象,并且它必须返回装饰后的函数。
您的
my_decorator
的第二个版本没有明确的 return
语句,因此它返回 None
。当通过 my_decorator
装饰器语法调用 @
时
before some_function() is called.
some fun
after some_function() is called.
被打印,然后
None
被分配给名称 just_some_fun
。因此,如果您将 print(just_some_fun)
添加到该代码的末尾,它将打印 None
。
如果我们摆脱
@
语法糖并使用正常的函数调用语法重新编写代码,可能会更容易理解发生了什么:
def my_decorator(some_fun):
print("before some_function() is called.")
some_fun()
print("after some_function() is called.")
def just_some_fun():
print("some fun")
just_some_fun = my_decorator(just_some_fun)
Python 中的装饰器是可调用对象,在最简单的情况下是带有一个参数的函数,该参数是某个函数或类。装饰器应该再次返回它所采用的相同类型(因此,如果它采用函数,它应该返回函数)。重点是装饰器被调用的时间。
当您导入 Python 文件或直接运行它时,Python 解释器会遍历内容并收集有关定义了哪些类和函数的信息,如果在某些代码(而不是声明)上遇到它,它将执行它。
如果解释器在装饰器上遇到它需要装饰函数,则调用装饰器并用装饰器的返回值替换装饰函数。
假设您有以下代码:
@my_decorator
def my_function()
print("My_function")
相当于这个调用:
def my_function()
print("My_function")
my_function = my_decorator(my_function)
如果装饰器是这样的
def my_decorator(func):
print("decorated)
return 42
那么
my_function
甚至不是一个函数,它会是一个整数(你可以尝试 print(my_function)
)
所以当你将装饰器定义为
def my_decorator2(some_fun):
print("before")
some_fun()
print("after")
然后这个装饰器不返回任何内容(在Python中这意味着它返回
None
)。
@my_decorator2
def decorated():
print("inside")
打印
before
inside
after
但是调用
decorated()
会引发异常 'NoneType' object is not callable
,因为 decorated
被替换为 None
。
您应该始终创建返回一些有用的东西的装饰器,例如函数或类(通常是内部的“包装”函数)。有时从装饰器返回函数/类之外的其他东西可能很有用,但它通常会混淆您的代码并将其转换为完全不可维护的东西。
它已经解释了为什么要使用包装函数,出于好奇我只是给出 示例如果我们不需要包装函数我们可以做什么。
None
或 pass
def decorator_func(to_be_decorated_function):
print("Logging IN: Currrently in function")
to_be_decorated_function()
print("Logging OUT: Currrently in function")
def a(): None # or def a(): pass
return (a)
@decorator_func
def to_be_decorated_function():
print('October 16, 2000')
to_be_decorated_function()
# equivalent to
#to_be_decorated_function = decorator_func(to_be_decorated_function)
def decorator_func(to_be_decorated_function):
print("Logging IN: Currrently in function")
to_be_decorated_function()
print("Logging OUT: Currrently in function")
@decorator_func
def to_be_decorated_function():
print('October 16, 2000')
to_be_decorated_function # notice I'm just using the object and not callable function
# equivalent to
#decorator_func(to_be_decorated_function)
Logging IN: Currrently in function
October 16, 2000
Logging OUT: Currrently in function