概念
装饰器就是一个可以接受调用也可以返回调用的函数,该函数接受被装饰的函数作为其位置参数。 装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用
本质
装饰器可以让函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
因此定义装饰器的本质就是一个函数,只不过这个函数的功能是用来为其他函数添加额外的功能。
带参数的装饰器和不带参数的装饰器
不带参数的装饰器是普通的装饰器,需要两层函数。
带参数的装饰器可以看成是装饰器工厂,需要三层函数,因为要传递装饰器的参数,所以多了一层函数。
装饰器的简单使用:
不带参数的装饰器:
###定义装饰器
def check(func):
print("验证权限")
def inner(identify):
func(identify)
return inner
###装饰装饰器
@check
def f1(user_id):
if user_id=="root":
print("允许root用户操作")
else:
print(f"不允许{user_id}用户操作")
f1("root")
运行结果:
带参数的装饰器:
def deco(arg):
def inner1(func):
def _cost(a,b):
func(a,b)
print(f"装饰器的参数是{arg}")
return _cost
return inner1
@deco(1)
def fun1(a,b):
print(f"我是真正的函数体,{a}+{b}={a+b}")
fun1(1,3)
运行结果为:
这里可以看到,最外面的一层函数其参数是@deco(1)中的参数1,inner函数的参数是装饰器装饰的函数的引用,这里是fun1,最里面的函数的参数是func1函数的参数即1,3
作用/优点
装饰器最大的作用就是用来包装代码块,让其具有特定的功能。
装饰器有以下优点:
• 模块化且清晰明确
• 代码重用
• 装饰器是显式的,增强可读性
多个装饰器的顺序
当有两个装饰器来装饰用一个函数的时候。离函数近的装饰器先进行装饰,装饰器先装饰完后将整个装饰结果给第一个装饰器进行装饰
即常说的:封装时自内而外(自下而上),执行时自外而内(自上而下)
###实现多重装饰,先验证有没有登录,再验证权限够不够
def login_required(func):
print("开始权限的验证")
def inner(username,passwd):
if username=="root":
result=func(username,passwd)
return result
else:
print("权限不够")
exit(0)
return inner
def login_valid(func):
print("开始用户登录的验证")
def inner(username,passwd):
if passwd==123456:
print("用户登录成功!")
func(username,passwd)
return True
else:
print("密码错误")
return False
return inner
@login_valid ##验证登录是否成功
@login_required #验证有没有权限
def login(username,passwd):
print("欢迎root用户")
login("root",123456)
运行结果为:
可以看到结果封装的时候是从下向上进行封装的,,但是执行的时候是先判断登录再判断权限,因次执行时是自上而下的顺序
使用例子
日志
import time
def input_log(name):
import logging
###获取logger对象
logger = logging.getLogger() ###提供日志文件可使用的接口,直接获取的是root logger (不取名的是默认logger对象)
# logger=logging.getLoger("name") 则会创建名为name的logger对象。继承root logger对象,root logger对象相当于是对整个logger的配置。然后声明子对象,继承root logger。在配置好的环境之上进行操作
##创建Handler
fh = logging.FileHandler("test2.log",encoding="utf-8") ##创建一个输出到指定test.log文件的Handler
ch = logging.StreamHandler() ##创建一个输出到控制台的Handler
##创建一个formatter的日志格式
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s") # 格式为时间-当前logger的对象名-运行的日志等级-日志信息
##绑定formatter到Handler上
fh.setFormatter(formatter) ###设置文件输出对象的格式
##绑定handler到logger上
logger.handlers.clear() #清空绑定的handler对象
logger.addHandler(fh)
logger.addHandler(ch)
# logging.basicConfig(level=logging.DEBUG) ##设置的是logging的函数的等级
logger.setLevel(level=logging.DEBUG)
logger.debug(f"执行了{name.__name__}函数") ###name.__name__获得当前的函数名
logger.info("logger info message")
logger.warning("this is warning message")
logger.error("this is error message")
logger.critical("this is critical message")
def log(func):
print("log")
def inner(b):
a=func(b)
input_log(func)
return a
return inner
@log
def fun2(a):
b=a+2
time.sleep(1)
print("func2 result:",b)
return b
fun2(2)
运行结果:
装饰器实现类对象按照创建时间排序
import functools
import time
####定义按创建时间排序的装饰器
def sortable_by_create_time(cls):
original_init=cls.__init__
@functools.wraps(original_init)
def new_init(self,*args,**kwargs):
original_init(self,*args,**kwargs)
self.create_time=time.time()
cls.__init__=new_init
cls.__lt__=lambda self,other:self.create_time<other.create_time
return cls
@sortable_by_create_time
#####创建一个类
class Sortable():
def __init__(self,identifier): ##初始化对象
self.identifier=identifier
self.create_time=time.time()
def __repr__(self): ###返回对象的说明信息
return self.identifier
yy=Sortable("yy")
time.sleep(0.1)
first=Sortable("first")
time.sleep(0.1)
second=Sortable("second")
time.sleep(0.1)
third=Sortable("third")
result=[first,second,third,yy]
print(sorted(result)) #sorted会自动去找类对象排序的行为
运行结果: