文章目录
装饰器是修改其他函数的功能的函数
函数
Python 中可以将函数传递给一个变量
def func():
print("say hello")
a = func
print(a) # <function func at 0x0000025F271C6DC0>
a() # say hello
func() # say hello
删除原函数看看会发生什么
del func
print(a) # <function func at 0x0000025F271C6DC0>
print(func) # name 'func' is not defined
我们还可以在函数内部定义一个函数,并将其赋值给其他变量(函数名也当做变量)
def func():
def say():
print("say hello")
return say
def not_say():
print("say goodbye")
not_say = func()
print(not_say) # <function func.<locals>.say at 0x0000025F271C68B0>
not_say() # say hello
可以看到,我们通过函数调用,将函数 say
赋值给了函数 not_say
第一个装饰器
def func_decorator(a_func):
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
def my_func():
print("I am the function which needs some decoration to remove my foul smell")
my_func()
#outputs: "I am the function which needs some decoration to remove my foul smell"
my_func = func_decorator(my_func)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
my_func()
#outputs:I am doing some boring work before executing a_func()
# I am the function which needs some decoration to remove my foul smell
# I am doing some boring work after executing a_func()
这就是 Python 装饰器做的事情,他们封装一个函数,并且用这样或那样的方式来修改它的行为,那么用 @
符号如何表示呢?
@func_decorator
def my_func():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
my_func()
#the @func_decorator is just a short way of saying:
# my_func = func_decorator(my_func)
@func_decorator
其实就是 my_func = func_decorator(my_func)
,功能是改变当前函数的功能(这里是 my_func
)
但是这里有一个问题,这样做相当于将原还是 my_func
覆盖了,直接变成了 wrapTheFunction
print(my_func.__name__) # wrapTheFunction
这并不是我们想要的,我们只想改变原函数的功能,仍希望能够访问原函数的其他属性
- Python提供了函数
functools.wraps
@wraps
接受一个函数来进行装饰,并加入了复制函数名称,注释文档,参数列表等功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性
from functools import wraps
def func_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
@func_decorator
def my_func():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to "
"remove my foul smell")
print(my_func.__name__) # my_func
应用
日志(Logging)
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called
类作装饰器
要使用类作为装饰器,需要在类内定义__call__
方法。
__call__
是一种 magic method,可以将该类的实例像函数一样被调用
class Person:
def __init__(self) -> None:
self.num = 10
self.name = "nsy"
def __call__(self):
print(self.num)
a = Person()
a() # 10, 这里就是调用了 __call__ 方法
我们将类作为装饰器
class Person:
def __init__(self, func) -> None:
self.num = 10
self.name = "nsy"
self.func = func
def __call__(self, *args):
print("Process before my func")
self.func(*args)
print("Process after my func")
@Person
def say_name(name): # say_name = Person(say_name), 实例化了一个对象
print(f"my name is {
name}")
say_name("nsy") # 调用 __call__ 方法
- 这里实际上还是相当于
say_name = Person(say_name)
,这就创建了一个Person
对象实例,之后我们在调用say_name("nsy")
时就是调用了__call__
方法,这样就将类作为装饰器了