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() 函數的返回結果依然是一個生成器,並不是是列表。

未完待續。。。

相關文章
相關標籤/搜索