装饰器介绍:
#装饰器:是一种程序设计模式,主要用于给函数添加一些额外功能(比如统计函数运行时间等)
# 又不希望通过继承或者修改源代码的方式去实现,就使用装饰器
#将要添加功能的函数作为内函数,将功能加在外函数内和内函数外
#装饰器本质是闭包,它需要把一个callable对象作为参数传递进来
#callable对象包含函数
import time
# def func1():
# print("I am func1")
# outer_time = time.time()
# time.sleep(1)
# def func2():
# print("I am func2")
# inner_time=time.time()
# print(inner_time-outer_time)
# return func2
#
# start=time.time()
# f=func1()
# f()
# end=time.time()
# print(f"运行花了{end-start}s")
# #使用装饰器
# def runtime(func):#func作为外函数给内函数的传值 √
# def inner():
# start = time.time()
# result=func()
# end = time.time()
# print(f"执行{func.__name__}花费了{end-start}")
# return result#将被加过功能(装饰)的传入函数作为内函数的返回值
# return inner# 返回内函数 √
# # @是修饰符,一般用于装饰器 语法糖
# @runtime #fun2=runtime(func2)
# #表示使用runtime装饰器,
# # 相当于将func2作为runtime的传值再将经过修饰器修改后的函数传回赋值给func2执行
# #最后运行的func2是装饰器中的inner函数
# def func2():
# time.sleep(2)
# print("I am func2")
# func2()#就是运行inner函数,可断点调试查看过程
# @runtime #需要装饰器中加的功能就加@runtime,不用就不加
# def func3():
# time.sleep(3)
# print("I am func3")
# func3()
# print(f"函数名:{func3.__name__}")
# #输出结果为inner,表面确实最后执行函数为inner而不是func3
# #写一个装饰器,进行日志记录
# import logging
# def log(func):
# def inner():
# logger = logging.getLogger()
# # 处理器,决定日志发送到哪里
# treat = logging.FileHandler("test.log") # 日志写入文件
# # 格式器
# # 定义一个格式
# Log_format = "%(asctime)s - %(pathname)s:%(lineno)d-%(levelname)s : %(message)s"
# # 给格式器设定以上格式
# formatter = logging.Formatter(Log_format)
# # 为写入文件的处理器treat绑定该种格式器
# treat.setFormatter(formatter)
# # 将handler处理器绑定到logger对象(日志器)上
# logger.addHandler(treat)
# # 默认情况下只有warning以上的日志才会记录
# logger.setLevel(logging.DEBUG) # 开启调试,记录DEBUG等级以上的日志
# logger.info("function test is used")
# result=func()
# return result
# return inner
# @log
# def test():
# global x
# x=100
# test()
#或者:
from logset import logger
def log(func):
def inner():
result=func()
logger.info(f"函数{func.__name__}已经执行")
return result
return inner
@log
def test():
print("i am func 4")
test()
带参数的装饰器:
import time
#不带参数的装饰器,使用两层函数定义
#带参数的装饰器,使用三层函数定义
def deco(flag):
def runtime(func):
def inner(*args,**kwargs):
print(f"带参数的装饰器{flag}")
start = time.time()
result = func(*args,**kwargs)
end=time.time()
print(f"执行{func.__name__}花费{end-start}s")
return result
return inner
return runtime
# runtime=deco(flag=1)
# func1=runtime(func1)
@deco(flag=1)
def func1():
print("i am func1")
time.sleep(2)
func1()
装饰器应用:
#1、权限认证
#2、统计运行时间
#3、日志记录
from logset import logger
import time
from functools import wraps
#运行时间装饰器
def runtime(func):#func作为外函数给内函数的传值 √
#解决log装饰器在runtime后执行时识别函数为inner的问题
@wraps(func) #保留元数据,将传进去的func的元数据全部复制給inner
def inner(*args,**kwargs):
start = time.time()
result=func(*args,**kwargs)
end = time.time()
print(f"执行{func.__name__}花费了{end-start}")
return result#将被加过功能(装饰)的传入函数作为内函数的返回值
return inner# 返回内函数 √
#日志记录装饰器
def log(func):
def inner(*args,**kwargs):
result=func(*args,**kwargs)#加上*args,*kwargs,让装饰器更加通用
#接受可变长位置参数和可变长关键字参数,让装饰器更通用
logger.info(f"函数{func.__name__}已经执行")
time.sleep(1)
return result
return inner
# #可以应用多个装饰器,但是要注意装饰器的执行顺序
# @runtime #后装饰,这时运行时间包括了log的inner函数时间与test函数的时间,不准确
# @log #先装饰
# def test():
# print("I am test")
# time.sleep(2)
# test()
# def test2(a,b):
# time.sleep(1)
# return a+b
# result=test2(1,3)
# print(result)
#可以应用多个装饰器,但是要注意装饰器的执行顺序
@log #后装饰,这时log识别的是runtime的inner函数,不准确
@runtime#先装饰 inner=runtime(test)
# 在runtime中用@wraps装饰后就将test元数据(函数名等)传给了runtime的inner
# 这样test的函数名等得以保留到log进行函数识别
def test():
print("I am test")
time.sleep(2)
test()
def test2(a,b):
time.sleep(1)
return a+b
result=test2(1,3)
print(result)
用类实现装饰器:
import time
class A:
def __init__(self,func):
self.func=func
def __call__(self,*args,**kwargs):
start = time.time()
time.sleep(1)
end = time.time()
result=self.func(*args,**kwargs)
print(end-start)
return result
class B:
def __init__(self,username):
self.username=username
def __call__(self,func):
def inner(*args,**kwargs):
start = time.time()
time.sleep(1)
end = time.time()
result=func(*args,**kwargs)
print(end-start)
return result
return inner
# @A
# def func1():
# print("I am func1")
# func1()
@B("username")
def func2():
print("I am func2")
func2()