Python装饰器的具体实用示例
示例1:普通装饰器
def name(n):def func(x):res = n(x+x)return resreturn func@name
def run(x): # run = name(run)print(x)if __name__ == '__main__':run(1)
# 2
def name(n):def func(*x):res = n(x+x)return resreturn func@name
def run(x): # run = name(run)print(x)if __name__ == '__main__':run(1)
# (1, 1)
上述二者的比较,注意传参参数。一个是普通的传值,一个是两个元组相加。
示例2:普通装饰器传值
def name(n):def func(x, y):res = n(x,y)return resreturn func@name
def run(x, y): # run = name(run)print(x, y)if __name__ == '__main__':run(1, 2)
# 1 2
试想,如何才能实现1+2,run函数中还是name函数中
def name(n):def func(x, y):res = n(x,y)return resreturn func@name
def run(x, y): # run = name(run)print(x + y)if __name__ == '__main__':run(1, 2)
在run函数中实现,name函数作用近似于调用的操作,也可以在name函数中实现
def name(n):def func(x, y):res = n(x,y)print(x + y)return resreturn func@name
def run(x, y): # run = name(run)# print(x + y)passif __name__ == '__main__':run(1, 2)
示例3-进阶:日志
import loggingdef name(n):def func(x, y):res = n(x,y)logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s ''%(lineno)d %(message)s', level=logging.DEBUG)logging.info("执行了{},{},结果是{}".format(x,y,res))return resreturn func@name
def run(x, y): # run = name(run)return x+yif __name__ == '__main__':run(1, 2)
# 2023-03-01 12:24:10,474 root 20 ceshi_test.py 10 执行了1,2,结果是3
这里的结果貌似没有指明函数,影响不大,可以看看logging模块,也可以自己加。
import loggingdef name(n):def func(x, y):res = n(x,y)logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s ''%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)logging.info("执行了{},{},{},结果是{}".format(n.__name__,x,y,res))return resreturn func@name
def run(x, y): # run = name(run)return x+yif __name__ == '__main__':run(1, 2)
# 2023-03-01 12:35:15,283 root 20 ceshi_test.py 9 func 执行了run,1,2,结果是3
可以看到,获取的运行函数其实不太一样。要想准确的获取,建议手写
示例4-进阶:时间计时器
import time
def timer(clock):def func(*args,**kwargs):start = time.time()res = clock(*args,**kwargs)print("耗时 {} S".format(time.time() - start))return resreturn func@timer
def run(x, y): time.sleep(1)print(x + y)if __name__ == '__main__':run(1, 2)
# 3
# 耗时 1.0103626251220703 S
上述是在不做任何操作的情况下,单纯用来计算程序运行时间。
示例5-再进阶-带参
def outwapper(out):def country(cont):def inwapper(*args,**kwargs):if out == '中国':print("你好啊,兄弟")else:print("你是哪个国家的")cont(*args,**kwargs)return inwapperreturn country@outwapper("中国")
def people():passif __name__ == '__main__':people()
是不是看起来麻烦了很多,仔细一看其实也久那么回事。传个参数,该返回的值还是得返回。
def outwapper(out):def country(cont):def inwapper(*args,**kwargs):if out == '中国':print("你好啊,兄弟")else:print("你是哪个国家的")cont(*args,**kwargs)return inwapperreturn country@outwapper("中国")
@outwapper("俄罗斯")
def people():passif __name__ == '__main__':people()
# 你好啊,兄弟
# 你是哪个国家的
可以多个装饰器作用同一个函数上,也能重复使用。
示例6-高阶-类装饰器
class Time(object):def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print(args,kwargs)@Time
def name():passif __name__ == '__main__':name()
套用格式即可,__init__中的参数是必须的,因为需要传递函数。
class Time(object):def __init__(self, func):self.func = funcdef __call__(self, *args, **kwargs):print(args,kwargs)@Time
def name(x,y):passif __name__ == '__main__':name('清安',age=18)
# ('清安',) {'age': 18}
很明显了吧,__call__中用来接收值并处理的。
传参
class Time(object):def __init__(self, func):self.func = funcdef __call__(self, evt):def wapper(*args, **kwargs):print(self.func, args, kwargs)return wapper@Time("中国")
def name(x, y):passif __name__ == '__main__':name('清安', age=18)
# 中国 ('清安',) {'age': 18}
evt是啥?
class Time(object):def __init__(self, func):self.func = funcdef __call__(self, evt):def wapper(*args, **kwargs):print(evt.__name__, args, kwargs)return wapper@Time("中国")
def name(x, y):print(x,y)if __name__ == '__main__':name('清安', age=18)
# name ('清安',) {'age': 18}
就是name函数的函数地址,如何使用evt参数呢?
class Time(object):def __init__(self, func):self.func = funcdef __call__(self, evt):def wapper(*args, **kwargs):evt(args,kwargs)# print(evt.__name__, args, kwargs)return wapper@Time("中国")
def name(x, y):print(x,y)if __name__ == '__main__':name('清安', age=18)
就是这么简单。
示例7-高阶-装饰类的装饰器
def func(cls):def inwapper(*args,**kwargs):print(cls.__name__)print(args)return inwapper@func
class User:def __init__(self,name):self.name = nameif __name__ == '__main__':User("清an")
# User
# ('清an',)
类中函数使用装饰器
def func(cls):def inwapper(x, *args, **kwargs):logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s ''%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))return inwapper# @func
class User:@funcdef name(self, name, name1, age):# return name, name1, agepass
if __name__ == '__main__':u = User()u.name("清安","ANAN",age=18)
2023-03-01 18:36:36,310 root 20 ceshi_test.py 74 inwapper 执行了name,结果是<__main__.User object at 0x0000020A11DABE50>,('清安', 'ANAN'),{'age': 18}
为什么要有个x,因为self会被当作参数传递,直接把内存地址一起传走了,要么下标取值要么再来个参数接收这个self。要么类中不使用self
❝既然使用了self,那么装饰器中能用来调用属性吗,答案是当然可以。
❞
def func(cls):def inwapper(x, *args, **kwargs):logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s ''%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)x.info = 1logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))return inwapperclass User:info = None@funcdef name(self, name, name1, age):# return name, name1, agepass
if __name__ == '__main__':u = User()u.name("清安","ANAN",age=18)print(u.info)
# 1
# 2023-03-02 09:15:36,640 root 20 ceshi_test.py 75 inwapper 执行了name,结果是<__main__.User object at 0x0000021B20A2F5B0>,('清安', 'ANAN'),{'age': 18}
❝显而易见,赋值成功。再来看看对其他函数赋值。
❞
def func(cls):def inwapper(x, *args, **kwargs):logging.basicConfig(format='%(asctime)s %(name)s %(levelno)s %(filename)s ''%(lineno)d %(funcName)s %(message)s', level=logging.DEBUG)x.Info("QA",18)logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs))return inwapperclass User:info = None@funcdef name(self, name, name1, age):# return name, name1, agepassdef Info(self,name,age):print("我是{},今年{}".format(name,age))if __name__ == '__main__':u = User()u.name("清安","ANAN",age=18)
# 2023-03-02 09:19:26,910 root 20 ceshi_test.py 75 inwapper 执行了name,结果是<__main__.User object at 0x00000232FF01F5B0>,('清安', 'ANAN'),{'age': 18}
# 我是QA,今年18
示例8-伪装
from functools import wrapsdef timer(value):def func(fun):# @wraps(fun)def inner(*args,**kwargs):res = fun()print(value)print(inner.__name__)return resreturn innerreturn func@timer("QA")
def run():passif __name__ == '__main__':run()
❝伪装装饰器,让装饰器函数名称指向运行函数名。
❞
此外还有一些用法,此处就不再阐述,学习完上述的示例后,你是否能自己写出一个像样的装饰器呢?