装饰器

tech2024-07-24  60

装饰器

概念本质带参数的装饰器和不带参数的装饰器不带参数的装饰器:带参数的装饰器: 作用/优点多个装饰器的顺序使用例子日志装饰器实现类对象按照创建时间排序

概念

装饰器就是一个可以接受调用也可以返回调用的函数,该函数接受被装饰的函数作为其位置参数。 装饰器通过使用该参数来执行某些操作,然后返回原始参数或一些其他的调用

本质

装饰器可以让函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。

因此定义装饰器的本质就是一个函数,只不过这个函数的功能是用来为其他函数添加额外的功能。

带参数的装饰器和不带参数的装饰器

不带参数的装饰器是普通的装饰器,需要两层函数。 带参数的装饰器可以看成是装饰器工厂,需要三层函数,因为要传递装饰器的参数,所以多了一层函数。

装饰器的简单使用:

不带参数的装饰器:

###定义装饰器 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会自动去找类对象排序的行为

运行结果:

最新回复(0)