Python3 CookBook | 迭代器与生成器

本文首发于知乎专栏,欢迎关注。 知乎专栏传送门python

如下测试代码所有基于 Python3。bash

反向迭代

想要反向迭代一个序列很容易,使用内置函数 reversed() 即可以作到,以下:函数

In [1]: a = [1, 2, 3, 4]
 
In [2]: for x in reversed(a):
   ...:     print(x)
   ...:
4
3
2
1
复制代码

反向迭代的特色是,须要预先知道迭代对象的大小,或者对象实现了 __reversed__() 方法,若是二者都不符合,那么,必须先将对象转换成一个列表才能够。测试

# Print a file backwards
f = open('somefile')
for line in reversed(list(f)):
    print(line, end='')
复制代码

有一个须要注意的问题就是,若是迭代对象元素不少的话,在转换成列表的过程当中会耗费大量的内存。ui

想解决这个问题,能够在自定义类上实现 __reversed__() 方法来解决,代码以下:spa

#!/usr/bin/env python
#-*- encoding: utf-8 -*-
 
def reverse_iterate(): 
	for rr in reversed(Countdown(30)):
		print(rr)
	for rr in Countdown(30):
		print(rr)
 
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 当使用reversed函数翻转对象时调用
	def __reversed__(self):
		n = 1
		while n <= self.start:
			yield n
			n += 1
 
 
if __name__ == '__main__':
	reverse_iterate()
复制代码

这个方法可使代码很是的高效,由于它再也不须要将数据填充到一个列表中,而后再去反向迭代这个列表。code

迭代器切片

在处理列表相关问题时,使用切片操做很是方便,但遗憾的是,迭代器并不支持标准的切片操做,主要缘由就是由于,咱们事先并不知道迭代器和生成器的长度。对象

In [3]: def count(n):
   ...:     while True:
   ...:         yield n
   ...:         n += 1
   ...:
 
In [4]: c = count(0)
 
In [5]: c[10: 20]
-----------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-60489cd5ce42> in <module>()
> 1 c[10: 20]
 
TypeError: 'generator' object is not subscriptable
复制代码

想在迭代器和生成器上使用切片操做,可使用 itertools.islice() 函数:排序

In [6]: import itertools
 
In [7]: for x in itertools.islice(c, 10, 20):
   ...:     print(x)
   ...:
10
11
12
13
14
15
16
17
18
19
复制代码

可是这里有一个问题,islice() 函数会消耗掉传入的数据,好比我再调用一次这个函数,返回的结果就发生了变化。ip

In [8]: for x in itertools.islice(c, 10, 20):
   ...:     print(x)
   ...:
   ...:
30
31
32
33
34
35
36
37
38
39
复制代码

因此,若是想屡次使用切片的结果,就须要把数据存起来。

顺序迭代合并后的排序迭代对象

假设如今有多个排序序列,如今想把它们合并,而且获得一个新的排序序列,应该怎么作呢?

heapq.merge() 函数能够完美解决这个问题:

In [9]: import heapq
 
In [10]: a = [1, 4, 7, 10]
 
In [11]: b = [2, 5, 6, 11]
 
In [12]: heapq.merge(a, b)
Out[12]: <generator object merge at 0x1087ab570>
 
In [13]: for x in heapq.merge(a, b):
	...:     print(x)
	...:
1
2
4
5
6
7
10
11
复制代码

须要注意的一点是,传入的序列必须是排过序的。

若是序列中元素过多,也并不须要担忧效率问题,经过上面代码也能够看出,heapq.merge() 函数的返回结果依然是一个生成器,并不是是列表。

未完待续。。。

相关文章
相关标签/搜索