一、什么是装饰器
作用:装饰器的作用就是为已经存在的对象添加额外的功能。
本质:本质上是一个 Python 函数或类,可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能。
应用场景:经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。可以抽离出大量与函数功能本身无关的雷同代码到装饰器中并继续重用。
二、基础知识
Python和Java不一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数:
def test1():
print("test1")
def test2(func):
func()
test2(test1)
场景思考:
如果需要在下面的这个函数中记录下函数的执行日志
def test1():
print("test1")
可以在代码中直接添加日志代码:
def test1():
print('test1')
logging.info("test1 is running")
但如果函数test2()、test3() 也有类似的需求呢?在每一个函数中去添加logging代码?这样就造成大量雷同的代码。装饰器的作用在这个时候就体现出来了。
三、具体应用
3.1 统计方法的耗时
#统计运行时间装饰器
def run_time(function):
@wraps(function) #@wraps也是一个装饰器,用于把原函数的元信息拷贝到装饰器里面的function函数。不加这个的话,原函数的信息会被wrapper取代
def wrapper():
time_start=time.time()
function()
time_end=time.time()
cost_time=time_end - time_start
print("花费时间:{}秒".format(cost_time))
return wrapper #注意这里不要带(),否则会报错
@run_time
def task():
time.sleep(1)
print("函数名称是:%s"% task.__name__)
if __name__=='__main__':
task()
输出结果:
3.2 日志打印装饰器+业务逻辑函数需要参数
#业务逻辑函数需要参数的情况
def use_logging(function):
@wraps(function)
def wrapper(*args, **kwargs): # *args是一个数组,**kwargs是一个字典
logging.warning("%s is running" %function.__name__)
return function(*args,**kwargs)
return wrapper
@use_logging
def foo(name, age=None, height=None):
print("I am %s, age %s, height %s" %(name, age, height))
if __name__=='__main__':
foo("yytest",age="18", height="180cm")
输出结果:
3.3 装饰器也可以带参数,提供更高的灵活性,比如不同业务函数可能需要的日志级别是不一样的
#装饰器带入参的情况
def logging_level(level):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs): # *args是一个数组,**kwargs是一个字典
if level == "warn":
logging.warning("%s is running" %function.__name__)
elif level == "info":
logging.info("%s is running" %function.__name__)
return function(*args,**kwargs)
return wrapper
return decorator
@logging_level(level="info")
def student(name, score=None):
print("I am %s, score is %s" %(name, score))
if __name__=='__main__':
student("wahaha",score=90)
输出结果:
3.4 整体练习使用代码:
"""
该类主要用于练习装饰器使用
"""
from functools import wraps
import logging
import time
#默认生成的root logger的level是logging.WARNING,低于该级别的就不输出了,因此这里设置一下日志输出级别为logging.INFO
logging.getLogger().setLevel(logging.INFO)
#统计运行时间装饰器
def run_time(function):
@wraps(function) #@wraps也是一个装饰器,用于把原函数的元信息拷贝到装饰器里面的function函数。不加这个的话,原函数的信息会被wrapper取代
def wrapper():
time_start=time.time()
function()
time_end=time.time()
cost_time=time_end - time_start
print("花费时间:{}秒".format(cost_time))
return wrapper #注意这里不要带(),否则会报错
#业务逻辑函数需要参数的情况
def use_logging(function):
@wraps(function)
def wrapper(*args, **kwargs): # *args是一个数组,**kwargs是一个字典
logging.warning("%s is running" %function.__name__)
return function(*args,**kwargs)
return wrapper
#装饰器带入参的情况
def logging_level(level):
def decorator(function):
@wraps(function)
def wrapper(*args, **kwargs): # *args是一个数组,**kwargs是一个字典
if level == "warn":
logging.warning("%s is running" %function.__name__)
elif level == "info":
logging.info("%s is running" %function.__name__)
return function(*args,**kwargs)
return wrapper
return decorator
@run_time
def task():
time.sleep(1)
print("函数名称是:%s"% task.__name__)
@use_logging
def foo(name, age=None, height=None):
print("I am %s, age %s, height %s" %(name, age, height))
@logging_level(level="info")
def student(name, score=None):
print("I am %s, score is %s" %(name, score))
if __name__=='__main__':
task()
foo("mytest",age="18", height="180cm")
student("wahaha",score=90)
四、python中常用的装饰器
@ddt:自动化测试数据驱动装饰器
@staticmethod:静态函数装饰器,使用后可以不需要实例化,直接类名.方法名()来调用
@property:标记类的方法装饰器,把一个方法变成属性调用,快速实现set和get方法
具体使用场景,后续文章中我再介绍~
以上就是本篇文章的全部内容,如果对你有帮助,
欢迎扫码关注程序员杨叔的微信公众号,获取更多全栈测试干货内容资料: