2.1. 迭代器与生成器
2.1.1. 手动遍历迭代器
In [5]: a = iter(range(1,3))
In [6]: next(a)
Out[6]: 1
In [7]: next(a)
Out[7]: 2
In [8]: next(a)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
Cell In[8], line 1
----> 1 next(a)
StopIteration:
In [10]: b=next(a,None)
In [11]: b
In [12]: b is None
Out[12]: True
2.1.2. 代理迭代
class Node(object):
def __init__(self, value):
self._value = value
self._children = []
def __repr__(self):
return f'Node({self._value})'
def add_child(self, node):
self._children.append(node)
def __iter__(self):
return iter(self._children)
if __name__ == "__main__":
root = Node(0)
child1 = Node(3)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
for ch in root:
print(ch)
2.1.3. 使用生成器创建新的迭代模式
def frange(start, stop, increment):
x = start
while x < stop:
yield x
x += increment
def countdown(n):
print('start ')
while n>0:
yield n
n-=1
print('done')
if __name__ == "__main__":
for n in frange(0, 4, 0.5):
print(n)
# symbol: frange
# hover info: (function) def frange(
# start: Any,
# stop: Any
2.1.4. 实现迭代器协议
class Node(object):
def __init__(self,value) -> None:
self._value = value
self._child = [ ]
def __repr__(self) -> str:
return 'Node({!r})'.format(self._value)
def add_child(self,node):
self._child.append(node)
def __iter__(self):
return iter(self._child)
def depth_first(self):
yield self
for c in self:
yield from c.depth_first()
# def width_first(self):
# # yield self
# yield from self._child
# for c in self:
# yield from c.width_first()
class NodeV2(object):
def __init__(self,value) -> None:
self._value = value
self._child = [ ]
def __repr__(self) -> str:
return 'Node({})'.format(self._value)
def add_child(self,node):
self._child.append(node)
def __iter__(self):
return iter(self._child)
def depth_first(self):
return DepthFirstIterator(self)
# todo DepDepthFirstIterator
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))
child2.add_child(Node(5))
# 0
# 1 2
# 3 4 5
#
for ch in root.depth_first():
print(ch)
print('-'*20)
# for ch in root.width_first():
# print(ch)
2.1.5. 反向迭代
使用内置的 reversed() 函数 。
class Countdown(object):
def __init__(self, start):
self.start = start
# Forward iterator
def __iter__(self):
n = self.start
while n > 0:
yield n
n -= 1
# Reverse iterator
def __reversed__(self):
n = 1
while n <= self.start:
yield n
n += 1
for r in reversed(Countdown(30)):
print(r)
2.1.6. 带有外部状态的生成器函数
from collections import deque
class linehistory(object):
def __init__(self,lines,max_size) -> None:
self.lines = lines
self.max_size = max_size
self.history = deque(maxlen=self.max_size)
def __iter__(self):
for lineno,line in enumerate(self.lines,1):
self.history.append((lineno,line))
yield line
def clear(self):
self.history.clear()
if __name__ == "__main__":
with open('./somefile.txt') as f:
lines = linehistory(f,3)
for line in lines:
if 'python' in line:
for lineno,hline in lines.history:
print(f'{lineno}:{hline}')
2.1.7. 迭代器切片
def countdown(n):
print('start ')
while n>0:
yield n
n-=1
print('done')
if __name__ == "__main__":
c = countdown(10)
# c[0:3]
import itertools
res = itertools.islice(c,0,3)
for i in res:
print(i)
2.1.8. 跳过可迭代对象的开始部分
def countdown(n):
print('start ')
while n>0:
yield n
n-=1
print('done')
from itertools import dropwhile
res = dropwhile(lambda n:n>=5,countdown(10))
for i in res:
print(i)
2.1.9. 排列组合的迭代
排列:
itertools.permutations()
组合:
itertools.combinations()
带重复:
itertools.combinations_with_replacement()
In [1]: items = ['a', 'b', 'c']
In [2]: import itertools
In [3]: list(itertools.combinations(items,2))
Out[3]: [('a', 'b'), ('a', 'c'), ('b', 'c')]
In [4]: list(itertools.combinations_with_replacement(items,2))
Out[4]: [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')]
In [5]: list(itertools.permutations(items,2))
Out[5]: [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
2.1.10. 序列上索引值迭代
In [6]: a=['a','b','c']
In [7]: for lineno,item in enumerate(a,1):
...: print(lineno,item)
...:
1 a
2 b
3 c
2.1.11. 同时迭代多个序列
In [8]: l1 = ['a','b','c']
In [9]: l2 = ['A','B','C']
In [10]: l3 = [1,2,3]
In [12]: for i in zip(l1,l2,l3):
...: print(i)
...:
('a', 'A', 1)
('b', 'B', 2)
('c', 'C', 3)
In [13]: dict(zip(l1,l2))
Out[13]: {'a': 'A', 'b': 'B', 'c': 'C'}
In [14]: for a,b in zip(l1,l2):
...: print(a,b)
...:
a A
b B
c C
2.1.12. 不同集合上元素的迭代
# Inefficent
for x in a + b:
...
# Better
for x in chain(a, b):
2.1.13. 创建数据处理管道
todo
2.1.14. 展开嵌套的序列
from collections.abc import Iterable
def flatten(item,ignore_types=(str,bytes)):
for x in item:
if isinstance(x,ignore_types):
yield x
elif isinstance(x, Iterable) :
yield from flatten(x)
else:
yield x
items = [1, 2, [3, 4, [5, 6], 7], 8,'abc']
print(list(flatten(item=items)))
2.1.15. 顺序迭代合并后的排序迭代对象
In [1]: a=[1,3,5,7]
In [2]: b=[0,2,4,8,6]
In [3]: import heapq
In [5]: list(heapq.merge(a,b))
Out[5]: [0, 1, 2, 3, 4, 5, 7, 8, 6]