1手动遍历迭代器
想遍历一个可以迭代对象中的所有元素,但是却不想使用for循环
使用next()函数并在代码中捕获StopIteration异常,迭代期间的基本细节.
def manual_iteration():with open('cookie.txt') as f:try:while True:line=next(f)print(line,end='')except StopIteration:pass
manual_iteration()
2代理迭代
问题:构建了一个自定义容器,里面包括列表,元祖和其他可迭代对象,希望直接在新容器对象上执行迭代操作
# 重构__repr__方法后,不管直接输出对象还是通过print打印的信息都按我们__repr__方法中定义的格式进行显示了
# 你会发现,直接输出对象时并没有按我们__str__方法中定义的格式进行输出,而用print输出的信息却改变
class Node:def __init__(self,name):self._name=nameself._children=[]def __repr__(self):return 'Node({})'.format(self._name)def add_child(self,node):self._children.append(node)def __iter__(self):return iter(self._children)
node1=Node(1)
node=Node(0)
node2=Node(2)
node.add_child(node1)
node.add_child(node2)
for ch in node:print(ch)了
解决方案:定义一个__iter__()方法,将迭代操作代理到容器内部的对象上去,这里的iter函数的使用简化了代码,iter(s)只是简单地通过s.__iter__()方法来返回对应的迭代器对象,就跟len(s)会调用s.__len__()原理是一样的
3使用生成器创建新的迭代模式
问题:自定义迭代模式...跟range() reversed()不一样
def frange(start,stop,step):x=startwhile x<stop:yield xx+=step
for i in frange(1,10,2):print(i)
一个函数需要有一个yield语句既可以将其转换成生成器,生成器只能用于迭代操作
一个生成器函数主要特征是它只会回应在迭代中使用到的next操作,一旦生成器函数返回退出,迭代终止..
def frange(start,stop,step):x=startwhile x<stop:x+=stepreturn x
for i in frange(1,10,2):print(i)
也就是说yield就免去了自己创建一个list的操作,也不需要多占用内存
4实现迭代器协议
问题:支持迭代操作的自定义对象
深度优先遍历属性节点的生成器
#生成树形节点
class Node:def __init__(self,name):self._name=nameself._children=[]def __repr__(self):return 'Node({})'.format(self._name)def add_child(self,node):self._children.append(node)def __iter__(self):return iter(self._children)def depth_first(self):yield selffor i in self._children:yield from i.depth_first()
node1=Node(1)
root=Node(0)
node2=Node(2)
root.add_child(node1)
root.add_child(node2)
node1.add_child(Node(3))
node1.add_child(Node(4))
node2.add_child(Node(5))
for ch in root.depth_first():print(ch)
5反向迭代一个序列
使用内置的reversed()函数.也可以通过在自定义类上实现反向迭代
class CountDown:def __init__(self,start):self.start=startdef __iter__(self):n=self.startwhile n>0:yield nn-=1def __reversed__(self):n=1while n<=self.start:yield nn+=1
for i in CountDown(3):print(i)for i in reversed(range(3)):print(i)
6带有外部状态的生成器函数
问题:你想定义一个生成器函数,但是它会调用某个你想暴露给用户的外部状态值
解决方案:如果你想让你的生成器暴露外部状态给用户,可以简单就将其生成一个类,然后把生成器函数放到__iter__()方法中过去
from collections import deque
class linehistory():def __init__(self,lines,histlen=3):self.lines=linesself.history=deque(maxlen=histlen)def __iter__(self):for lineno,line in enumerate(self.lines):self.history.append(line)yield linedef clear(self):self.history.clear()with open('cookie.txt') as f:lines=linehistory(f)print(lines)for line in lines:print(line)
想暴露谁yield谁....其他的不可见
7迭代器切片
函数itertools.islice()正好适用于迭代器和生成器上做切片操作
def count(n):while n<20:yield nn+=1
c=count(0)
import itertools
for x in itertools.islice(c,10,20):print(x)
8跳过可迭代对象的开始部分
itertools模块中有一些函数可以完成,itertools.dropwhile(),传递一个函数对象和一个可迭代对象,丢弃函数返回True的原有序列
from itertools import dropwhile
li=['#a','#b','#1','2']
for i in dropwhile(lambda line:line.startswith('#'),li):print(i,end='')
#明确知道哪个位置不想要可以用islice(item,index,None)
9排列组合的迭代
迭代遍历一个集合中元素的所有可能的排列或组合
itertools.permutations()接收一个集合并产生一个元组序列,每个元组由集合中所有元素的一个排列组成,也就是说通过打乱集合中元素排列顺序生成一个元组
from itertools import permutations
for i in permutations(li):print(i)for i in permutations(li,2):print(i)#指定长度的序列itertools.combinations 输入集合中元素的所有组合
对于combinations来讲,元素的顺序已经不重要了,('a','b')和('b','a')等价itertools.combinations_with_replacement()允许同一个元素被选取多次
10序列上索引值迭代
迭代一个序列的同时跟踪正在被处理的元素索引
内置的enumerate
11同时迭代多个序列
想同时迭代多个序列,每次分别从一个序列中取一个元素
为了同时迭代多个序列,使用zip函数
x=[1,2,3,4,5]
y=[1,2,445,56]
for m,n in zip(x,y):print(m,n)
zip(a,b)会产生一个可返回元组(x,y)的迭代器,一旦某个序列到底结尾,迭代宣告结束,因此迭代长度跟参数中最短序列长度一致
itertools.zip_longest()函数 匹配最长的序列长度 zip zip_longest()都可以添加fillvalue=0这个参数
12不同集合上元素的迭代
不同容器中的对象的避免重复的迭代
itertools.chain() 方法可以简化这个任务,接受一个可迭代对象作为输入,并返回一个迭代器,有效的屏蔽掉在多个容器中迭代细节
from itertools import chain
for i in chain(x,y):print(i)
使用chain()的一个常见场景是当你想对不同几个中所有元素执行操作的时候,将集合放到set里面去..
itertools.chain()接受一个或者多个可迭代对象作为输入参数,然后创建一个迭代器,依次连续的返回每个可迭代对象中的元素
13创建数据处理管道(150)
问题:以数据管道(类似Unix管道)的方式迭代处理数据,比如,有个大量的数据需要处理,但是你不能将其一次性放入内存里面
解决方案:定义一个由多个特定任务独立任务的简单生成器组成的容器
14展开嵌套的序列 yield from 相当于 for item in items:yield item 就是返回迭代器里面全部的内容的意思
from collections import Iterable
def flattern(items,ignore_type=(str,bytes)):for item in items:if isinstance(item,Iterable) and not isinstance(item,ignore_type):yield from flattern(item)else:yield item
items=[1,2,[3,4,[5,6],7],8]
for x in flattern(items):print(x)
yield from 在涉及到基于协程和生成器的并发编程中扮演着更加重要的角色
15顺序迭代合并后的排序迭代对象(排序好的)
heapq.merge()函数可以解决
import heapq
x=[1,2,3,4,5]
y=[1,2,445,56]
for i in heapq.merge(x,y):print(i)
16迭代器代替while无限循环
需要调用某个函数或者一般迭代模式不同的测试条件
def reader(s):while True:data=s.recv(CHUNKSIZE)if data==b'':breakprocess_data(data)
def reader(s):for chunk in iter(lambda: s.recv(CHUNKSIZE),b''):pass#process_data(data)
iter函数有一个特性就是它接受一个可选的callable对象和一个标记(结尾)值作为输入参数,当以这种方式使用的时候,它会创建一个迭代器,这个迭代器会不断调用callable对象直到返回值和标记值相等为止