装饰器,迭代器,生成器
装饰器
def function(f):
def inner(*args,**kwagrs):
start = time.time()
ret = f(*args,**kwagrs)
end =time.time() - start
print('程序运行时间为%.4f'% end)
return ret
return inner
@function
def code(n):
for i in range(n):
print(i)
code(10000)
print(code.__name__)#inner
'''
变量名.__name__ 查看实际调用函数名
实际是调用inner,被装饰方法名无法获取
解决:添加一个内置的装饰器@wraps()
from functools import wraps
def function(f):
@wraps(f)
def inner(*args,**kwagrs):
ret = f(*args,**kwagrs)
return ret
return inner
@function
def code(n):
for i in range(n):
print(i)
code(10000)
print(code.__name__)
'''
带参数的装饰器
根据标记值的不同来决定是否增强代码
f = True
d = False
def function(flag):
def timmer(f):
def inner(*args,**kwagrs):
ret = f(*args,**kwagrs)
if flag:
print(f.__name__ + '代码已经增强')
return ret
return ret
return inner
return timmer
@function(f)
def test1():
print('test1函数')
@function(d)
def test2():
print('test2函数')
test1()
test2()
多个装饰器装饰一个函数
def function(f):
def inner(*args,**kwagrs):
print('装饰器---1----before')
ret = f(*args,**kwagrs)
print('装饰器---1----after')
return ret
return inner
def function2(f):
def inner2(*args,**kwagrs):
print('装饰器---2----before')
ret = f(*args,**kwagrs)
print('装饰器---2----after')
return ret
return inner2
@function2
@function
def test1():
print('test1函数')
test1()
'''
装饰器---2----before
装饰器---1----before
test1函数
装饰器---1----after
装饰器---2----after
执行流程
@function2等价于test1 = function2(test1)等价于function2(function(test1))即function2(inner)
@function等价于test1 = function(test1)返回inner
test1() 调用 function2(inner)()等于inner2(),inner2()中f=inner,f()就是inner()
'''
迭代器
可迭代协议:
只要含有__iter__方法的都是可迭代的
list,dict,set,tuple,enumerate都是可迭代的
dir(class) 获取class类中所有的方法
迭代器协议:
只要含有__iter__方法和__next__方法的都是迭代器
迭代器是一个可以记住遍历的位置的对象
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
同一个迭代器对象中的值只能取一次
print(dir([]))#获取列表所有方法名 ,其中有_iter_
#通过可迭代对象得到一个对应的迭代器
re= [].__iter__()
print(re)
'''
迭代器常用的3个方法:
__length_hint__ ()返回迭代器中元素个数
__setstate__()从指定位置处开始迭代
__next__()取出迭代器中下一个值,没有值,会抛出StopIteration异常,以终止迭代
'''
l=[3,5,6,8,9,8]
re= l.__iter__()#获取一个迭代器
print(re)#<list_iterator object at 0x00000000006CD3C8>
for i in re:#同一个迭代器
print(i)#3 5 6 8 9 8
for i in re:#同一个迭代器
print(i)#无输出,同一个迭代器对象只能取一次值
l=[3,5,6,8,9,8]
for i in l:#同一个对象
print(i)#3 5 6 8 9 8
for i in l:#同一个对象
print(i)#3 5 6 8 9 8
'''
for循环的本质:基于迭代器协议提供了一个统一的可以遍历所有对象的方法,
即在遍历之前,先调用对象的__iter__方法将其转换成一个对应的迭代器,
然后使用迭代器的__next__方法依次循环元素,当元素循环完时,
会触发StopIteration异常,for循环会捕捉到这种异常,终止迭代;
'''
如何确定一个对象是可迭代的还是迭代器
from collections.abc import Iterable,Iterator
l=[]
print(isinstance(l, Iterable))#True 判定l对象是否可迭代
print(isinstance(l, Iterator))#False 判定l对象是否是迭代器
生成器
生成器本质是迭代器
生成器一次只能产生一个值,在需要时再去生成值,节省内存
生成器的应用方式
1.生成器函数
2.生成器表达式
生成器函数
def generator():
for i in range(15):
yield '生成器%d' % i
g = generator()
print(g)#<generator object generator at 0x0000000000572F48>
print(g.__next__())
'''
含有yield关键字的函数都是生成器函数
yield关键字只能在函数内部
有yield就不能有return
yield可以将后面的值返回,和return类似
yield执行后代码未结束。等待下一次取值,从此次断点继续执行
生成器函数执行后会得到一个生成器,此时函数内代码不会执行
真正获取值的时候,内部代码才会执行
生成器函数取值的方法
1.__next__() 一次取一个值,需要处理最后一个值输出后的StopIteration异常
2.for循环 如果没有break,会一次读取完所有的值
3.强制类型转换
list(g) 会将所有数据一次性加载到内存中
4.send() 不能用来取第一个yield值,既能取值,也能传值
'''
生成器表达式
e=(i for i in range(10))#得到一个生成器
print(e)#<generator object <genexpr> at 0x0000000000472EC8>
st = (y + x for x in '345' for y in '♠♥♣♦')
for i in st:
print(i,end = ' ')#♠3 ♥3 ♣3 ♦3 ♠4 ♥4 ♣4 ♦4 ♠5 ♥5 ♣5 ♦5
生成器进阶
send() :生成器方法,获取生成器的下一个值,和next类型,同时传一个值给当前的yield表达式
#获取移动平均值
def generator():
su = 1
count = 1
while 1:
nu = yield su / count
su += nu
count += 1
g = generator()
print(g.__next__())#1.0
print(g.send(5))#3.0
print(g.send(6))#4.0
对于生成器的send(),第一次必须用__next__()后才能使用或者send(None)。可以与装饰器配合
def adornment(f):
def inner(*args,**kwargs):
g = f(*args,**kwargs)
g.__next__()#或者 next(g) 本质是调用了g.__next__()
return g
return inner
@adornment
def generator():
su = 1
count = 1
while 1:
nu = yield su / count
su += nu
count += 1
g = generator()#装饰器执行
print(g.send(5))#3.0
print(g.send(6))#4.0
yield from 应用
def generator1(l1):
yield from l1
l = '345'
g = generator1(l)
for i in g :
print( i ,end = ' ')#3 4 5
查询文件中指定内容,并返回当前行内容
def check_Content(fileName,keyword):
with open(fileName, encoding = 'utf-8' ) as f:
for i in f :
if keyword in i :
yield i
g = check_Content('filedown','天使')
for i in g:
print(i,end = ' ')
yield 转载https://blog.csdn.net/jason_cuijiahui/article/details/84947310
def consumer():
r = ''
while True:
n = yield r
if not n:
return
print('[CONSUMER] Consuming %s...' % n)
r = '200 OK'
def produce(c):
c.send(None)
n = 0
while n < 5:
n = n + 1
print('[PRODUCER] Producing %s...' % n)
r = c.send(n)
print('[PRODUCER] Consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
文件夹中查找指定文件内容返回文件名 转载:https://www.cnblogs.com/Eva-J/articles/7213953.html
import os
from functools import wraps
#第一步
def init(func):
#第三步——list_files
#第五步——opener
#第七步——cat
#第九步——grep
#第十一步——printer
@wraps(func)
def wrapper(*args,**kwargs):
#第十三步——printer
#第十六步——grep
#第十九步——cat
#第二十二步——opener
#第二十五步——list_files
print(func.__name__)#查看被装饰的方法名 printer grep cat opener list_files
g=func(*args,**kwargs)
next(g)
#第十五步——printer
#第十八步——grep
#第二十一步——cat
#第二十四步——opener
#第二十七步——list_files
return g
return wrapper
#第二步
@init
def list_files(target):
while 1:
#第二十六步——list_files
dir_to_search=yield #传入一个目录路径
#第二十九步
for top_dir,dir,files in os.walk(dir_to_search):#遍历一个目录内各个子目录和子文件
#top_dir 是dir_to_search代表目录的路径
#dir 是dir_to_search下所有子目录的名字组成的列表
#top_dir 是dir_to_search下非目录文件的名字组成的列表。
for file in files: #遍历列表 获取文件名
#第三十步
#第四十步
target.send(os.path.join(top_dir,file)) #给opener(target)的yield表达式传入一个文件的绝对地址
#第四步
@init
def opener(target):
while 1:
#第三十九步
#第二十三步——opener
file=yield
#第三十一步
#第四十一步
fn=open(file) #根据传入的文件地址打开这个文件
target.send((file,fn)) #给cat(target)的yield表达式传入文件地址和文件操作对象
#第六步
@init
def cat(target):
while 1:
#第三十八步
#第二十步
file,fn=yield
#第三十二步
#第四十二步
for line in fn: #通过文件操作对象获取文件内容
target.send((file,line)) #给grep(pattern,target)的yield表达式传入文件地址和一行文件内容
#第八步
@init
def grep(pattern,target):
while 1:
#False #第三十五步
#False #第三十六步
#False #第三十七步
#。。。。。
#第十七步
file,line=yield
#第三十三步
#第四十三步
if pattern in line: #判断这一行文件内容中是否有关键字pattern
#True 第四十四步
target.send(file) #如果有关键字就给printer()的yield表达式传入文件地址
#False #第三十四步
#第十步
@init
def printer():
while 1:
#第四十七步
#第十四步
file=yield
#第四十五步
if file:
#第四十六步
print(file) #输出含有关键字的文件的地址
#第十二步
g=list_files(opener(cat(grep('python',printer())))) #得到生成器
#第二十八步
g.send(r'E:\test')
yield函数面试题
def dome():
for i in range(5):
yield i
g = dome()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1)) #[0, 1, 2, 3, 4]
print(list(g2)) #[]
#生成器只能取一次值
def add(n,i):
return n+i
def test():
for i in range(4):
yield i
g=test()
for n in [3,6,9]:
g=(add(n,i) for i in g)
print(list(g))#[27, 28, 29, 30]
'''
for n in [3,6,9]:
g=(add(n,i) for i in g)
解析
n = 3
g=(add(n,i) for i in g)
n = 6
g=(add(n,i) for i in g)
n = 9
g=(add(n,i) for i in g)
所以只需要看n=9时g的值即可
n = 9
g=(add(n,i) for i in g)
=(add(n,i) for i in ((add(n,i) for i in g)))
=(add(n,i) for i in ((add(n,i) for i in (add(n,i) for i in g))))
=(add(9,i) for i in ((add(9,i) for i in (add(9,i) for i in range(4)))))
=(add(9,i) for i in ((add(9,i) for i in (9,10,11,12))))
=(add(9,i) for i in ((18,19,20,21)))
=(27,28,29,30)
'''