示例1:普通装饰器
def name(n): def func(x): res = n(x+x) return res return 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 res return 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 res return 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 res return 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 res return func @name def run(x, y): # run = name(run) # print(x + y) pass if __name__ == '__main__': run(1, 2)
示例3-进阶:日志
import logging def 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 res return func @name def run(x, y): # run = name(run) return x+y if __name__ == '__main__': run(1, 2) # 2023-03-01 12:24:10,474 root 20 ceshi_test.py 10 执行了1,2,结果是3
这里的结果貌似没有指明函数,影响不大,可以看看logging模块,也可以自己加。
import logging def 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 res return func @name def run(x, y): # run = name(run) return x+y if __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 res return 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 inwapper return country @outwapper("中国") def people(): pass if __name__ == '__main__': people()
是不是看起来麻烦了很多,仔细一看其实也久那么回事。传个参数,该返回的值还是得返回。
def outwapper(out): def country(cont): def inwapper(*args,**kwargs): if out == '中国': print("你好啊,兄弟") else: print("你是哪个国家的") cont(*args,**kwargs) return inwapper return country @outwapper("中国") @outwapper("俄罗斯") def people(): pass if __name__ == '__main__': people() # 你好啊,兄弟 # 你是哪个国家的
可以多个装饰器作用同一个函数上,也能重复使用。
示例6-高阶-类装饰器
class Time(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print(args,kwargs) @Time def name(): pass if __name__ == '__main__': name()
套用格式即可,__init__中的参数是必须的,因为需要传递函数。
class Time(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print(args,kwargs) @Time def name(x,y): pass if __name__ == '__main__': name('清安',age=18) # ('清安',) {'age': 18}
很明显了吧,__call__中用来接收值并处理的。
传参
class Time(object): def __init__(self, func): self.func = func def __call__(self, evt): def wapper(*args, **kwargs): print(self.func, args, kwargs) return wapper @Time("中国") def name(x, y): pass if __name__ == '__main__': name('清安', age=18) # 中国 ('清安',) {'age': 18}
evt是啥?
class Time(object): def __init__(self, func): self.func = func def __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 = func def __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 = name if __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: @func def name(self, name, name1, age): # return name, name1, age pass 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 = 1 logging.info("执行了{},结果是{},{},{}".format(cls.__name__,x, args, kwargs)) return inwapper class User: info = None @func def name(self, name, name1, age): # return name, name1, age pass 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 inwapper class User: info = None @func def name(self, name, name1, age): # return name, name1, age pass def 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 wraps def timer(value): def func(fun): # @wraps(fun) def inner(*args,**kwargs): res = fun() print(value) print(inner.__name__) return res return inner return func @timer("QA") def run(): pass if __name__ == '__main__': run()
❝伪装装饰器,让装饰器函数名称指向运行函数名。
❞
此外还有一些用法,此处就不再阐述,学习完上述的示例后,你是否能自己写出一个像样的装饰器呢?