目录
前言
在Python编程中,装饰器是一种高级语法,它为函数或类提供了额外的功能,而无需修改其本身的代码。装饰器的应用场景广泛,例如,需要记录函数的执行时间或自动处理异常等场景是时,装饰器都能派上用场。通过装饰器,我们可以将横切关注点与核心功能分离,使代码更加清晰、可维护,并且易于扩展。
一、 装饰器
装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。
它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景,装饰器是解决这类问题的绝佳设计。
有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
1.装饰器引入前案例1
案例1:在执行函数的时候,除了正常执行函数外,还有要输出下日志信息
import loggingdef fun1():
print('执行fun1函数')
logging.warning("日志信息:fun1函数在执行")def fun2(name):
name()
print('执行fun2函数')
logging.warning("日志信息:fun2函数在执行")# fun1函数作为参数传给fun2函数
fun2 (fun1)
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#输出结果:
# 执行fun1函数
# 执行fun2函数
# WARNING:root:日志信息:fun1函数在执行
# WARNING:root:日志信息:fun2函数在执行
2.装饰器引入前案例2
为了减少重复写代码,我们可以重新定义一个新的函数:专门处理日志 ,日志处理完之后再执行真正的业务代码
#解决方法:将处理日志提取出来放在一个单独的函数中,日志处理完之后再执行真正的业务代码import logging
def loginfo(fun_name):
logging.warning('{}函数在执行'.format(fun_name.__name__))
fun_name()def fun1():
print('执行fun1函数')def fun2 ():
print('执行fun2函数')# loginfo(fun1)
loginfo(fun2)
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# 输出结果:
# WARNING:root:fun1函数在执行
# 执行fun1函数
# WARNING:root:fun2函数在执行
# 执行fun2函数
3.产生问题
这样做逻辑上是没问题的,功能是实现了,但是我们调用的时候不再是调用真正的业务逻辑 fun1函数,而是换成了 use_logging 函数,这就破坏了原有的代码结构,现在我们不得不每次都要把原来的那个 fun1 函数作为参数传递给 use_logging 函数,那么有没有更好的方式的呢?当然有,答案就是装饰器
4.装饰器定义
装饰器:本意是为了优化程序的代码,增强函数的逻辑性
规则:在需要执行函数的头部,加上@符号 -- 如果存在这个@后面的函数名称,就会先去执行这个函数
自定义的log函数,加上fun_name的这种写法,是装饰器函数,那么调用装饰器,就按照上述的规则去执行就可以了
# 装饰器的固定写法:
def log(fun_name):
def wrapper():
代码块。。。
return wrapper
# 装饰器调用:
@log
def test():
pass
在这个装饰器函数里面,存在一个fun_name(可以自定义)参数,按照装饰器的执行规则,会用来接收调用函数的本体
想调用装饰器,就需要在调用函数的头部,加一个@符号,并且后面跟上装饰器函数的名称
在执行的时候,会默认把调用函数的本体,传给装饰器函数的参数,然后会去执行装饰器里面的内置函数
#使用装饰器来解决执行函数添加日志,并且不改变调用方式的问题
import logging
# 装饰器定义
def loginfo(fun_name):
def wrapper():
logging.warning('{}函数在执行'.format(fun_name.__name__))
return fun_name()
return wrapper
# 装饰器使用
@loginfo
def fun1():
print('执行fun1函数')
@loginfo
def fun2 ():
print('执行fun2函数')
fun1()
fun2()
#>>>>>>>>>>>>>>>>>>>>>>>>>>
#输出结果:
# WARNING:root:fun1函数在执行
# 执行fun1函数
# WARNING:root:fun2函数在执行
# 执行fun2函数
5.被装饰函数--带参数
如果调用装饰器的函数有些不带参数,有些带参数,带参数的个数也不确定该怎么处理?
我们可以在定义 wrapper 函数的时候指定参数: *args是一个数组,**kwargs一个字典,可以接受任意个参数(包括0个和多个)
"执行的函数带参不一致的处理"
import logging
def loginfo(fun_name):
def test(*args, **kwargs):
logging.warning('{}函数在执行'.format(fun_name.__name__))
return fun_name(*args, **kwargs)
return test
@loginfo
def fun1():
print('执行fun1函数')
@loginfo
def info(name, addr):
print('姓名:{},住址:{}'.format(name, addr))
fun1()
#>>>>>>>>>>>>>>>>>>>>>>>>>>>
# 输出结果:
# WARNING:root:fun1函数在执行
# 执行fun1函数
info(name='python', addr='北京')
#>>>>>>>>>>>>>>>>>>>>>>>>>>>
# WARNING:root:info函数在执行
# 姓名:python,住址:北京
总结
装饰器作为Python中的一个强大工具,装饰器扮演着至关重要的角色。它们能够动态地修改函数或类的行为,实现代码复用和模块化解耦。