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=name
self._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=start
while x<stop:
yield x
x+=step
for i in frange(1,10,2):
print(i)
一个函数需要有一个yield语句既可以将其转换成生成器,生成器只能用于迭代操作
一个生成器函数主要特征是它只会回应在迭代中使用到的next操作,一旦生成器函数返回退出,迭代终止..
def frange(start,stop,step):
x=start
while x<stop:
x+=step
return x
for i in frange(1,10,2):
print(i)
也就是说yield就免去了自己创建一个list的操作,也不需要多占用内存
4实现迭代器协议
问题:支持迭代操作的自定义对象
深度优先遍历属性节点的生成器
#生成树形节点
class Node:
def __init__(self,name):
self._name=name
self._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 self
for 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=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 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=lines
self.history=deque(maxlen=histlen)
def __iter__(self):
for lineno,line in enumerate(self.lines):
self.history.append(line)
yield line
def 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 n
n+=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'':
break
process_data(data)
def reader(s):
for chunk in iter(lambda: s.recv(CHUNKSIZE),b''):
pass
#process_data(data)
iter函数有一个特性就是它接受一个可选的callable对象和一个标记(结尾)值作为输入参数,当以这种方式使用的时候,它会创建一个迭代器,这个迭代器会不断调用callable对象直到返回值和标记值相等为止