迭代器 / 生成器
2021-08-13 本文已影响0人
慕知
一,迭代器
1,前提
# 1)单纯的重复不是迭代
while True:
msg = input('>>: ').strip()
print(msg)
# >>: 3
# 3
# >>: 4
# 4
# 2)while循环是一个迭代的过程
info=['aa','bb','cc','dd']
i=0
while i < len(info):
print(info[i])
i+=1
# aa
# bb
# cc
# # dd
2,可迭代对象
#索引进行迭代取值仅适用于:字符串,列表,元祖
#字典、集合等非序列类型不适用
#可迭代对象都能满足迭代取值
abc='good'
abc.__iter__() # .__iter__()打开的都是可迭代对象
info=[1,2,4]
info.__iter__()
3,迭代器对象
#1,迭代器对象内置的有iter和next方法的对象,打开的文件本身就是一个迭代器对象
#2,执行迭代器对象.iterm()方法得到的仍然是迭代器本身
#3,执行迭代器.next()方法就会计算出迭代器的下一个值
info=(1,4,5)
new=info.__iter__()
print(next(new))
print(next(new))
print(next(new))
# 1
# 4
# 5
注意事项:
# 1)如果再执行,超过了元祖定义的元素数量就会报错
print(next(new))
# print(next(new))
# StopIteratio
#2)以上迭代到最没有值会报错,如果想反复循环或者得出第一个值的需求,只能重新定义如下:
new=info.__iter__()
print(next(new))
... ...
4,for / while
实现StopIteration: #捕捉异常终止循环
# StopIteration: #捕捉异常终止循环
info={'lili','peter','ssen'}
i=iter(info)
while True:
try: #检测以下的语法
print(next(i))
except StopIteration: #捕捉到一场终止循环
break
# peter
# lili
# ssen
#for 循环实现迭代
abc=[1,2,3]
for i in abc:
print(i)
# 1
# 2
# 3
# 工作原理:
#1)先调用可迭代对象abc内置的iter方法拿到一个迭代对象
#2)调用该迭代器对象的next方法取到的值赋值给iterm,执行循环体完成一次循环
#3)知道捕捉到StopIteration异常,结束迭代
二,生成器
1)yield
例1)
# yield相当于return,返回当前函数
def foo():
print('111')
yield
print('222')
yield
print('333')
yield
f=foo().__iter__()
next(f)
#111
next(f)
# 111
# 222
next(f)
# 111
# 222
# 333
例2)
def foo(start,stop,step=1):
print('start...')
while start < stop:
yield start
start+=step
print('end...')
g=foo(0,3).__iter__()
print(g)
# <generator object foo at 0x1049e39e0>
print(next(g))
# start...
# 0
print(next(g))
# start...
# 0
# 1
print(next(g))
# start...
# 0
# 1
# 2
print(next(g)) # 会报错
# start...
# 0
# 1
# 2
# end...
# StopIteration
补充
def func():
print('11111')
yield 1
print('22222')
yield 2
print('33333')
yield 3
f=func()
print(f)
# <generator object func at 0x1034579e0> 生成器就是迭代器
res=next(f)
# 11111 只要出发next,就会触发函数本身,即使在赋值也会返回值
print(res)
# # 1
# 如果直接next方式如下
g=func()
g.__next__()
# 11111
g.__next__()
# 11111
# 22222
yield可以返回多次值;
函数的暂停和与再继续状态是由yield保存
2)yield表达式应用
示例1
def eater(name):
print('%s ready to eat' % name)
while True:
food=yield
print('%s start to eat %s' %(name,food))
e=eater('mz') # 生成一个迭代器
print(e)
# <generator object eater at 0x1006439e0>
# #初始化方式一:
# next(e)
# # mz ready to eat
#初始化方式二:
e.send(None)
# mz ready to eat
# 从暂停的位置传值给yield,yield再赋值给food
e.send('apple')
# mz ready to eat
# mz start to eat apple
# 继续传值,会再yield的状态下继续执行
e.send('banana')
# mz ready to eat
# mz start to eat apple
# mz start to eat banana
示例2
def eater():
print('吃什么呢')
while True:
food=yield
print('吃%s啦'% food)
f=eater()
print(f)
# <generator object eater at 0x104b239e0>
next(f) # 此步骤非常重要!必须要先执行一次!
# 需要事先”初始化”一次,让函数挂起在food=yield,等待调用g.send()方法为其传值
# ready to eat #执行结果
f.send('汉堡')
# 吃什么呢
# 吃汉堡啦
f.send('牛排')
# 吃什么呢
# 吃汉堡啦
# 吃牛排啦
示例升级版
def init(func):
def wrapper(*args,**kwargs):
g=func(*args,**kwargs)
next(g)
return g
return wrapper
@init
def eater():
print('吃什么呢')
while True:
food=yield
print('吃%s啦'% food)
a=eater()
# 吃什么呢
a.send('鸡腿')
# 吃什么呢
# 吃鸡腿啦
a.send('冰淇淋')
# 吃什么呢
# 吃鸡腿啦
# 吃冰淇淋啦
示例再升级版
def init(func):
def wrapper(*args,**kwargs):
f=func(*args,**kwargs)
next(f)
return f
return wrapper
@init
def eater():
print('吃什么呢')
food_list=[]
while True:
food=yield food_list
food_list.append(food)
a=eater()
print(a.send('蛋糕'))
# 吃什么呢
# ['蛋糕']
print(a.send('牛奶'))
# 吃什么呢
# ['蛋糕']
# ['蛋糕', '牛奶']
print(a.send('巧克力'))
# 吃什么呢
# ['蛋糕']
# ['蛋糕', '牛奶']
# ['蛋糕', '牛奶', '巧克力']
示例
# 实现tail -f的功能
import time
def tail(filepath):
with open(filepath,'rb') as f:
f.seek(0,2)
while True:
line=f.readline()
if line:
yield line
else:
time.sleep(0.2)
def grep(pattern,lines):
for line in lines:
line=line.decode('utf-8')
if pattern in line:
yield line
# 执行以下向access.log这个文件输入内容
with open('access.log',mode='at',encoding='utf-8') as f:
f.write("aaa404aa\n")
# 执行函数,便会出现以下内容
for line in grep('404',tail('access.log')):
print(line,end='')
#aaa404aa
分析:
# 函数里有yield,则以下是个迭代器(或生成器)
g=tail('access.log')
print(g)
# <generator object tail at 0x104f74510>
for line in g:
print(line)
#这个时候只要access.log这个文件出现新内容,就会输出到屏幕上