Python学习笔记——迭代器和生成器
1、手动遍历迭代器
使用next函数,并捕获StopIteration异常。
def manual_iter(): with open('./test.py') as f: try: while True: line = next(f) print line except StopIteration: pass
next函数也可以指定值来标记结尾
def manual_iter(): with open('./test.py') as f: try: while True: line = next(f, None) if line == None: break print line except StopIteration: pass
使用for循环操作迭代器就不用考虑StopIteration异常,底层自动处理这些细节
2、代理迭代
使用iter来返回指定对象的迭代,iter(s)
只是简单的通过调用 s.__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): return iter(self._children) node1 = Node(1) node2 = Node(2) root = Node('root') root.add_child(node1) root.add_child(node2)
i = iter(root)
print next(i)
print next(i)
for n in root:
print n
需要注意的是,实现了__iter__()可以使用for循环,但是不能直接使用next()进行调用,要想使用next,必须先调用root.iter()
3、实现迭代器协议
Python的迭代协议要求一个 __iter__()
方法返回一个特殊的迭代器对象, 这个迭代器对象实现了next 方法,注意python3中是__next__方法。并通过 StopIteration
异常标识迭代的完成。最简单的方式就是代理迭代中使用的方式。还有一种方式就是__iter__()返回对象本身,该对象实现next()方法。
class Fib(object): def __init__(self): self.a, self.b = 0, 1 # 初始化两个计数器a,b def __iter__(self): return self # 实例本身就是迭代对象,故返回自己 def next_(self): # 在python3中,为__next__() self.a, self.b = self.b, self.a + self.b # 计算下一个值 if self.a > 100000: # 退出循环的条件 raise StopIteration() return self.a # 返回下一个值
4、反向迭代
使用内置的reversed可以实现反向迭代,前提是对象大小可以确定,或者实现了__reversed__方法。
a = [1, 2, 3, 4] for x in reversed(a): print x
使用__reversed__方法
class Countdown: 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 rr in reversed(Countdown(30)): print rr for rr in Countdown(30): print rr
5、迭代器切片
对迭代器进行切片操作,可以使用itertools.islice()方法来实现,函数 islice()
返回一个可以生成指定元素的迭代器,它通过遍历并丢弃直到切片开始索引位置的所有元素。 然后才开始一个个的返回元素,并直到切片结束索引位置。
def count(n): while True: yield n n += 1 c = count(10) import itertools for x in itertools.islice(c, 10, 20): print x