|
一、functools.wraps
二、带参数的装饰器
三、多个装饰器装饰同一个函数
四、生成器函数
一、装饰器
(一)原则
开放封闭原则,对修改是封闭的。只能扩展功能
(二)作用
不改变原函数调用方式的情况下,在函数的前后添加功能,装饰器的本质是闭包函数。
def wrapper(func):# func是被装饰函数 def inner(*args,**kwargs): print('''被装饰前的操作''') ret = func(*args,**kwargs) # 被装饰函数,只是一个中间传话的 print('''在被装饰后的操作''') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): print('全体放假%s天'%day) return '好开心' ret = holiday(3) #实际上执行的是inner print(ret) ''' 被装饰前的操作 全体放假3天 在被装饰后的操作 好开心 '''
def outer(*args,**kwargs): print(args) print(*args) #接收是聚合,调用是打散 outer(1,2,3,4) ''' (1, 2, 3, 4) 1 2 3 4 '''
def outer(*args,**kwargs): print(args) print(*args) def inner(*args): print('inner:',args) inner(*args) outer(1,2,3,4) ''' (1, 2, 3, 4) 1 2 3 4 inner: (1, 2, 3, 4) '''
def wahaha(): ''' 一个打印哇哈哈的函数 :return: ''' print('哇哈哈') print(wahaha.__name__) # wahaha,输出字符串格式的函数名 print(wahaha.__doc__) # 打印函数注释
def wrapper(func):# func是被装饰函数 def inner(*args,**kwargs): print('''被装饰前的操作''') ret = func(*args,**kwargs) # 被装饰函数,只是一个中间传话的 print('''在被装饰后的操作''') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): print('全体放假%s天'%day) return '好开心' print(holiday.__name__) #输出结果为inner,holiday的内存地址已经传给inner了,全局中没有holiday了 # ret = holiday(3) #实际上执行的是inner print(ret)
二、带参数的装饰器
我们在使用 装饰器 的过程中,难免会损失一些原本的功能信息。
也就是说,原函数的属性失效了。
如果想要保留原函数的属性,就可以用到functools.wraps了。
1、functools.wraps 则可以将原函数对象的指定属性复制给包装函数对象, 默认有 module、name、doc,或者通过参数选择。代码如下:
from functools import wraps def wrapper(func):# func是被装饰函数 @wraps(func) #带参数的装饰器 def inner(*args,**kwargs): print('''被装饰前的操作''') ret = func(*args,**kwargs) # 被装饰函数,只是一个中间传话的 print('''在被装饰后的操作''') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): ''' 这是一个放假通知 :param day: :return: ''' print('全体放假%s天'%day) return '好开心' print(holiday.__name__) #输出结果为holiday print(holiday.__doc__) ret = holiday(3) #实际上执行的是inner print(ret) ''' holiday 这是一个放假通知 :param day: :return: 被装饰前的操作 全体放假3天 在被装饰后的操作 好开心 '''
代码执行过程
2、带参数装饰器的应用
需求:为了季度考核有500个函数需要执行,现在不需要了,但是以后可能还是会用到,如何在不改变原函数的基础上实现这个功能。若需要执行的函数过多,不需要执行此功能时,一个一个更改功能可能太麻烦,可设置一个全局变量对函数进行改进。
(1)未改进前的函数
import time def timer(func): def inner(*args,**kwargs): start = time.time() ret = func(*args,**kwargs) end = time.time() print(end-start) return ret return inner @timer def wahaha(): time.sleep(0.1) print('wahaha') @timer def erguotou(): time.sleep(0.1) print('erguotou') wahaha() erguotou() ''' wahaha 0.1007697582244873 erguotou 0.10069155693054199 '''
(2)改进的函数
import time FLAGE = True #当FLAGE = True执行装饰器,当FLAGE=False不执行,与之前的函数相比只是增加了一层装饰器 def timer_out(flag): def timer(func): def inner(*args,**kwargs): if flag: start = time.time() ret = func(*args,**kwargs) end = time.time() print(end-start) return ret else: ret = func(*args, **kwargs) return ret return inner return timer # 谁调用它,返回给谁,返回给@timer_out()中的timer_out # timer = timer_out(FLAGE) # @timer(FLAGE) @timer_out(FLAGE) #先调用timer_out,传参数FLAGE,接收timer_out参数的返回值timer,加上@符号就是@timer,和之前的一样 def wahaha(): time.sleep(0.1) print('wahaha') @timer_out(FLAGE) def erguotou(): time.sleep(0.1) print('erguotou') wahaha() erguotou()
三、多个装饰器装饰同一个函数
(1)双层装饰器
def wrapper1(func): #func->f def inner1(): print('wrapper1,before func') func() #f() print('wrapper1,after func') return inner1 def wrapper2(func): # func->inner1 def inner2(): print('wrapper2,before func') func() # inner1() print('wrapper2,after func') return inner2 @wrapper2 # f=wrapper2(f)->wrapper2(inner1)=inner2 @wrapper1 # f=wrapper1(f)=inner1 def f(): print('in f') f() # inner2 ''' wrapper2,before func wrapper1,before func in f wrapper1,after func wrapper2,after func '''
函数的执行过程
(2)三层装饰器
def wrapper1(func): def inner1(): print('wrapper1,before func') func() print('wrapper1,after func') return inner1 def wrapper2(func): def inner2(): print('wrapper2,before func') func() # inner1() print('wrapper2,after func') return inner2 def wrapper3(func): def inner3(): print('wrapper3,before func') func() # inner1() print('wrapper3,after func') return inner3 @wrapper3 @wrapper2 @wrapper1 def f(): print('in f') f() ''' wrapper3,before func wrapper2,before func wrapper1,before func in f wrapper1,after func wrapper2,after func wrapper3,after func ''' def wrapper1(func): def inner1(): print('wrapper1,before func') ret = func() print('wrapper1,after func') return ret return inner1 def wrapper2(func): def inner2(): print('wrapper2,before func') ret=func() print('wrapper2,after func') return ret return inner2 def wrapper3(func): def inner3(): print('wrapper3,before func') ret=func() print('wrapper3,after func') return ret return inner3 @wrapper3 @wrapper2 @wrapper1 def f(): print('in f') return 'hahaha' print(f()) ''' wrapper3,before func wrapper2,before func wrapper1,before func in f wrapper1,after func wrapper2,after func wrapper3,after func hahaha '''
四、生成器函数
1、只要含有yield关键字的函数都是生成器函数,yeild关键字只能写在函数里,且yeild和return不能同时存在。
生成器函数执行后会得到一个生成器作为返回值。
def generator(): print(1) yield 'a' # 生成器函数:执行之后会得到一个生成器作为返回值 ret = generator() print(ret) ''' <generator object generator at 0x0000021859F797C8> '''
def generator(): print(1) yield 'a' # 生成器函数:执行之后会得到一个生成器作为返回值 ret = generator() print(ret) print(ret.__next__()) # 生成器就是一个迭代器 ''' <generator object generator at 0x0000021859F797C8> 1 a '''
2、yield和return的区别
解释一:
就像打电玩一样,你蓄力发大招的时候,如果执行了return,就直接把大招发出去了,蓄力结束,如果执行了yield,就相当于返回一个生成器对象,每调用一次next(),就发一个大招。
解释二:
return是函数返回值,当执行到return,后续的逻辑代码不再执行
yield是创建迭代器,可以用for来遍历,有点事件触发的意思。
def generator(): print(1) yield 'a' print(2) yield 'b' g = generator() # g为生成器,generator()为生成器函数 ret = g.__next__() print(ret) ''' 1 a '''
def generator(): print(1) yield 'a' print(2) yield 'b' yield 'c' g = generator() # g为生成器,generator()为生成器函数 ret = g.__next__() print(ret) ret = g.__next__() print(ret) ret = g.__next__() print(ret) ''' 1 a 2 b c '''
def generator(): print(1) yield 'a' print(2) yield 'b' yield 'c' g = generator() # g为生成器,generator()为生成器函数 for i in g: print(i) ''' 1 a 2 b c '''
#哇哈哈%i def wahaha(): for i in range(20000): yield '哇哈哈%s'%i g = wahaha() count = 0 for i in g: count += 1 print(i) if count>5:#从生成的函数中取5个值 break print('****', g.__next__()) # 如果需要的话,还可以接着再取 ''' 哇哈哈0 哇哈哈1 哇哈哈2 哇哈哈3 哇哈哈4 哇哈哈5 **** 哇哈哈6 '''
列表是可迭代的,但不是迭代器
l = [1,2,3,4] for i in l: print(i) if i == 2: break for i in l: print(i) #循环结束后再次执行函数,从头开始
def wahaha(): for i in range(20000): yield '哇哈哈%s'%i g = wahaha() #g,g1相当于两个迭代器,各走各的。 g1 = wahaha() print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g1.__next__()) ''' 哇哈哈0 哇哈哈1 哇哈哈2 哇哈哈0 '''
def tail(filename): f = open('d:\\huangshurui.txt',encoding='utf-8') while True: line = f.readline() if line: print('****',line.strip('\r\n')) tail('huangshurui.txt') ''' **** 22111 **** 月儿 **** xinger **** 月儿 **** 星儿 **** nihao **** 噢噢噢噢 哦哦 '''
针对以上函数,我想实现在每行前面加上***后打印,除此之外还想在在每行加上。。。后打印,解决此问题,可采用生成器函数
def tail(filename): f = open('d:\\huangshurui.txt',encoding='utf-8') while True: line = f.readline() if line: yield line.strip('\r\n') g = tail('huangshurui.txt') for i in g: if '月儿' in i: #监听过滤的效果 print('****',i)
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-5-20 01:01
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社