装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。
装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。
装饰器的使用方法很固定
- 先定义一个装饰器(帽子)
- 再定义你的业务函数或者类(人)
- 最后把这装饰器(帽子)扣在这个函数(人)头上
就像下面这样子
# 定义装饰器
def decorator(func):
def wrapper(*args, **kw):
return func()
return wrapper
# 定义业务函数并进行装饰
@decorator
def function():
print("hello, decorator")
实际上,装饰器并不是编码必须性,意思就是说,你不使用装饰器完全可以,它的出现,应该是使我们的代码
- 更加优雅,代码结构更加清晰
- 将实现特定的功能代码封装成装饰器,提高代码复用率,增强代码可读性
1. 第一种:普通装饰器
首先咱来写一个最普通的装饰器,它实现的功能是:
- 在函数执行前,先记录一行日志
- 在函数执行完,再记录一行日志
# 这是装饰器函数,参数 func 是被装饰的函数
def logger(func):
def wrapper(*args, **kw):
print('我准备开始执行:{} 函数了:'.format(func.__name__))
# 真正执行的是这行。
func(*args, **kw)
print('主人,我执行完啦。')
return wrapper
假如,我的业务函数是,计算两个数之和。写好后,直接给它带上帽子。
@logger
def add(x, y):
print('{} + {} = {}'.format(x, y, x+y))
然后执行一下 add 函数。
add(200, 50)
来看看输出了什么?
我准备开始执行:add 函数了:
200 + 50 = 250
我执行完啦。
2. 第二种:带参数的函数装饰器
装饰器本身是一个函数,做为一个函数,如果不能传参,那这个函数的功能就会很受限,只能执行固定的逻辑。这意味着,如果装饰器的逻辑代码的执行需要根据不同场景进行调整,若不能传参的话,我们就要写两个装饰器,这显然是不合理的。
比如我们要实现一个可以定时发送邮件的任务(一分钟发送一封),定时进行时间同步的任务(一天同步一次),就可以自己实现一个 periodic_task (定时任务)的装饰器,这个装饰器可以接收一个时间间隔的参数,间隔多长时间执行一次任务。
由于这个功能略显复杂,此处就不贴代码了
那我们来自己创造一个伪场景,可以在装饰器里传入一个参数,指明国籍,并在函数执行前,用自己国家的母语打一个招呼。
# 小明,中国人
@say_hello("china")
def xiaoming():
pass
# jack,美国人
@say_hello("america")
def jack():
pass
那我们如果实现这个装饰器,让其可以实现 传参 呢?
会比较复杂,需要两层嵌套。
def say_hello(contry):
def wrapper(func):
def deco(*args, **kwargs):
if contry == "china":
print("你好!")
elif contry == "america":
print('hello.')
else:
return
# 真正执行函数的地方
func(*args, **kwargs)
return deco
return wrapper
来执行一下
xiaoming()
print("------------")
jack()
看下结果
你好!
------------
hello.
好了,今天就先到这里,下次小张学了新的再继续分享!!!