目录
4.1 手动访问迭代器中的元素
lis = [1,2,3,4]
#手动访问迭代器,next()函数,捕获StopIteration异常,这是告知迭代结束
for a in lis:
try:
while a<5:
lisit = iter(lis)
a = next(lisit)
print(a+1)
except StopIteration:
pass
#输出2 将无限循环下去
# 了解next函数的结构
lisit = iter(lis)
print(next(lisit)) #1
print(next(lisit)) #2
print(next(lisit)) #3
print(next(lisit)) #4
print(next(lisit)) # File "E:\vippython\Python CookBook\第四章 迭代器和生成器.py", line 22, in <module>
# StopIteration
4.2委托代理
# 我们想让列表、元组或其他可以迭代的对象能够完成迭代操作
#一般是定义一个__iter__()方法,将迭代请求传送给对象内部的容器上
class Node:
def __init__(self,value):
self._value = value
self._children = []
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self,node):
self._children.append(node)
def __iter__(self): #将迭代请求转发给._children的内部持有对象
return iter(self._children)
#调用
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
for ch in root:
print(ch)
#Node(1)Node(2)
4.3用生成器创建新的迭代模式
# 这一步和我们平时用的没有两样,首先定义一个浮点数的生成器函数
def frange(start,stop,step):
x = start
while x<stop:
yield x #函数中只要出现了yield 就变成了生成器,需要next()响应才能返回响应的值,只不过for语句能够处理好这些细节
x += step
for i in frange(0,4,0.5):
print(i) #0,0.5,1...
4.4 实现迭代协议
#使用生成器的方式实现以深度优先级返回的迭代器将会是一个极好的选择
class Node:
def __init__(self,value):
self._value = value
self._children = []
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self,node):
self._children.append(node)
def __iter__(self): #将迭代请求转发给._children的内部持有对象
return iter(self._children)
def depth_first(self): #在原来的类上加深一层函数
yield self #首先产出自身
for c in self:
yield from c.depth_first() #迭代子节点,,产生其他元素
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
child1.add_child((Node(3)))
child1.add_child((Node(4)))
child1.add_child((Node(5)))
for ch in root.depth_first():
print(ch)
# Node(0)
# Node(1)
# Node(3)
# Node(4)
# Node(5)
# Node(2)
4.5反向迭代
# 使用reversed()函数实现
a = [1,2,3,4]
for i in reversed(a):
print(i) #4,3,2,1
#如果迭代对象无法确定大小,使用实现__reversed__()特殊方法,这方法效率及高,并且对于大内存数据来说会更少的占用资源
class Countdown:
def __init__(self,start):
self.start = start
#向前迭代
def __iter__(self):
n = self.start
while n > 0:
yield n
n -= 1
#反向迭代
def __reversed__(self):
n = 1
while n <= self.start:
yield n
n += 1
for i in reversed(Countdown(5)):
print(i) #12345
for i in Countdown(5):
print(i) #54321
#当两个都不行时
# 将迭代对象转化为列表,在进行反向迭代
a = 'anything'
for line in reversed(list(a)):
print(line,end='')
4.6定义带有额外状态的生成器函数
# 将迭代器放在一个类中、
from collections import deque
class historyline:
def __init__(self,lines,histlen=3):
self.lines = lines
self.history = deque(maxlen=histlen)
def __iter__(self):
for lineno,line in enumerate(self.line,1):
self.history.append(lineno,line)
yield line
def clear(self):
self.history.clear()
with open('/nalvo/xiyouji') as f:
lines = historyline(f)
for line in lines:
if 'python' in line:
for lineno,hline in lines.history:
print('{}:{}'.format(lineno,hline))
4.7 迭代器的切片和跳过前一部分的元素
lis = [1,2,3,4,5,6,7,8,9,10]
import itertools
for i in itertools.islice(lis,3,5): #产生一个迭代器,然后进行迭代
print(i)
#一个有注释行的文件想要删除其中的前边的注释行
from itertools import dropwhile,islice
with open('ceshi.m3u8') as f:
for line in dropwhile(lambda line:line.startswith('#'),f):
# print(line,end='')
# http://valipl.cp31.ott.cibntv.net/6573094C4DA3D71A3B8FD3B1F/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00001.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=261508&vkey=Ba7234b21953eae21381b9cf1d3c44b29
# #EXTINF:10.000000,
# http://valipl.cp31.ott.cibntv.net/67748DF2D1C327156C6013155/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00002.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=426948&vkey=Bc828723125cfb3cde56aee46fdcb0fcc
# #EXTINF:10.000000,
#如果想要全文过滤
with open('ceshi.m3u8','r') as f:
lines = (line for line in f if not line.startswith('#'))
for line in lines:
print(line)
'''
http://valipl.cp31.ott.cibntv.net/697612985C84671E2AE5629E0/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00003.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=165816&vkey=B77ac86e6ea7a8c828fba4fc45d02c0b5
http://valipl.cp31.ott.cibntv.net/6573094C7294B7205A86B6BB1/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00004.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=303056&vkey=B719ede93cd923d38c934a4ea63d92b20
http://valipl.cp31.ott.cibntv.net/69761298E604071B8B5705176/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00005.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=285196&vkey=Bdc564121f6abf1518cb3e0b81d21a229
http://valipl.cp31.ott.cibntv.net/69761298F864571DBAF856753/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00006.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=308508&vkey=Bc57bd99145441892ba829fb6fb7c93f6
http://valipl.cp31.ott.cibntv.net/69761298897347164C3A3252B/03000600006041956E10F87011BA6AE07FF21F-03FC-4B96-9BCD-4B77EC117171-00007.ts?ccode=0512&duration=1493&expire=18000&psid=082ce795073f68f29f59c13b60cda50540346&ups_client_netip=&ups_ts=1650413127&ups_userid=&apscid=&mnid=&rid=2000000083F9ED4F661C79E84F0DB5FF08B22D7502000000&operate_type=1&umt=1&type=mp4hdv3&utid=RjzmGsoWG3oCASeQXxaiTYrR&vid=XMzk1NjM1MjAw&s=cc003400962411de83b1&sp=&t=e0e6aa837980685&cug=2&bc=2&si=5&eo=0&ykfs=350056&vkey=B5e7f6dc7c501ccfc1b911320349e66e4
'''
4.8迭代所有的组合和排序
lis = ['a','b','c','d']
from itertools import permutations #迭代所有的排序
for i in permutations(lis,3): #参数3为指定排序元素个数 数学中A
print(i)
'''
('a', 'b', 'c')
('a', 'b', 'd')
('a', 'c', 'b')
('a', 'c', 'd')
('a', 'd', 'b')
...
'''
from itertools import combinations #迭代所有的组合,相同元素不会因为排序不同而再次出现 数学中C
for i in combinations(lis,2):
print(i)
'''
('a', 'b')
('a', 'c')
('a', 'd')
...
'''
from itertools import combinations_with_replacement #允许在同一个元素在同一个元组中出现多次
for i in combinations_with_replacement(lis,3):
print(i)
'''
('a', 'a', 'a')
('a', 'a', 'b')
('a', 'a', 'c')
('a', 'a', 'd')
('a', 'b', 'b')
...
'''
4.9 以索引——值对的形式进行迭代
lis = ['a','b','c']
for idx,val in enumerate(lis,1): #参数1作为开始索引值,默认为0
print(idx,val)
'''
1 a
2 b
3 c
...
'''
# 这一步适用于记录文件中的行号,在错误信息时体现
word_summary = {}
with open('somefile.txt','r') as f:
lines = f.readlines()
for idx,line in enumerate(lines):
words = [w.strip().lower() for w in line.split()]
for word in words:
word_summary[word].append(idx)
print(word_summary) #打印输出一个有关键字和对应行号的字典
4.10 同时迭代多个序列
# 这一小节没有啥好说的,就一个简单的zip
names = ['dada','xixi','yuyu']
clas = ['a1','a2','a3']
age = [12,11,13]
for i in zip(names,clas,age): #zip()返回一个迭代器,如果直接打印,则需要将其转化为一个列表list(zip())
print(i)
#zip()是以最短的序列进行匹配,匹配完了就完了,多于的也不进行,使用zip_longest()匹配会匹配完
from itertools import zip_longest
a = ['a','b','c']
b = [1,2,3,4]
for i in zip_longest(a,b,fillvalue=0):
print(i)
'''('a', 1)
('b', 2)
('c', 3)
(0, 4)
...
'''
4.11 在不同的容器中进行迭代
# 如果有多个需要迭代的对象进行迭代,使用itertools.chain可以高效完成
a = ['a','b','c']
b = [1,2,3,4]
from itertools import chain
for i in chain(a, b):
print(i) #a b c 1 2 3 4
4.12扁平化处理嵌套的序列
# 使用yield from 产生递归生成器函数
from collections.abc import Iterable
def flatten (item,ignore_types=(str,bytes)):
for x in item:
if isinstance(x,Iterable) and not isinstance(x,ignore_types):
yield from flatten(x)
else:
yield x
items= [1,2,[3,[4,5],6],7]
for x in flatten(items):
print(x) #1234567
4.13合并多个有序序列,在对整个有序序列进行迭代
a = [1,2,3,4,5]
b = [5,4,3,2,1]
for c in heapq.merge(a,b): #这个函数不用将有序列表进行预先组合在堆中,因此只需要很小的开销就可以实现很长序列的输出
print(c) #1234554321
4.15 用迭代器代替while循环
import sys
f = open('ceshi.m3u8')
for i in iter(lambda :f.read(10),''):
n = sys.stdout.write(i)
print(n)
'''
XT-X-VERSI10
ON:3
#EXT-10
X-TARGETDU10
RATION:10
10
#EXT-X-MED10
IA-SEQUENC10
E:0
#EXTIN10
F:10.0000010
0,
http://10
valipl.cp310
1.ott.cibn10
tv.net/65710
3094C4DA3D10
...
'''