天天看點

白話Python疊代器與生成器結束語

疊代器

疊代是Python最強大的功能之一,是通路集合元素的一種方式。

疊代器是一個可以記住周遊的位置的對象,簡單的說,就是他隻記錄資料在記憶體中所在的位置,使用的是棧的邏輯記錄資料所在的記憶體位址,因為用的是棧的邏輯,是以隻需要記住棧的起始位址,以及棧的偏移量就可以得到所有資料的記憶體位址。

疊代器對象從集合的第一個元素開始通路,直到所有的元素被通路完結束。疊代器隻能往前不會後退。是以,疊代器可以存儲很多資料,而不占用很多記憶體空間,但是這個特性也導緻它無法反複讀資料,也就是“閱完即焚”。

疊代器有兩個基本的方法:iter() 和 next()。

字元串,清單或元組對象都可用于建立疊代器:

list=[1,2,3,4]
it = iter(list)    # 建立疊代器對象
print(it)
# 輸出結果:<list_iterator object at 0x000001499C6EA400>
print (next(it))   # 輸出疊代器的下一個元素
# 輸出結果:1
print (next(it))
# 輸出結果:2
           

由此可以看出,疊代器并不能直接輸出結果,他傳回的值是一個疊代器對象,隻能使用next方法來提取疊代器下一個元素。

那麼如果疊代器裡的資料很多,總不能一個接一個next的吧。

當然python肯定不會那麼蠢,是以疊代器對象也可以使用正常for語句進行周遊:

list=[1,2,3,4]
it = iter(list)    # 建立疊代器對象
for x in it:
    print (x, end=" ")
# 輸出結果:1 2 3 4
           

或者,while循環調用next提取元素

import sys         # 引入 sys 子產品
 
list=[1,2,3,4]
it = iter(list)    # 建立疊代器對象
 
while True:
    try:
        print (next(it),end=" ")
    except StopIteration:
        sys.exit()
# 輸出結果:1 2 3 4
           

建立一個疊代器

把一個類作為一個疊代器使用,需要在類中實作兩個方法 __iter__() 與 __next__() 。

如果你已經了解的面向對象程式設計,就知道類都有一個構造函數,Python 的構造函數為 __init__(), 它會在對象初始化的時候執行。

__iter__() 方法傳回一個特殊的疊代器對象, 這個疊代器對象實作了 __next__() 方法并通過 StopIteration 異常辨別疊代的完成。

__next__() 方法(Python 2 裡是 next())會傳回下一個疊代器對象。

為了友善說明這兩個方法,我們來建立一個傳回數字的疊代器,初始值為 1,逐漸遞增 1,并通過__next__()傳回遞增後的值:

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass)
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
'''
輸出結果:
1
2
3
4
5
'''
           

StopIteration

剛剛提到了StopIteration,這是什麼呢?這是一種異常,用于辨別疊代的完成,防止出現無限循環的情況,在 __next__() 方法中我們可以設定在完成指定循環次數後,通過raise觸發 StopIteration 異常來結束疊代。

比如,想要寫一個程式,在資料 20 次疊代後停止執行運作,那麼可以這麼寫:

class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 20:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)
'''
輸出結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'''
           

生成器

ok~說完疊代器,那麼我們再來看一個更神奇的内容,為什麼說它神奇呢?

因為在 Python 中,使用了 yield 的函數被稱為生成器(generator)。跟普通函數不同的是,生成器是一個傳回疊代器的函數,隻能用于疊代操作,更簡單點了解生成器就是一個疊代器,是以生成器生成的資料也隻能使用一次,“閱完即焚”。

在調用生成器運作的過程中,每次遇到 yield 時函數會暫停并儲存目前所有的運作資訊,傳回 yield 的值, 并在下一次執行 next() 方法時從目前位置繼續運作。

調用一個生成器函數,則會傳回的是一個疊代器對象。

我們使用 yield 來實作斐波那契數列,借此看一下生成器是什麼邏輯:

import sys
 
def fibonacci(n): # 生成器函數 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一個疊代器,由生成器傳回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()
# 輸出結果:0 1 1 2 3 5 8 13 21 34 55
           

結束語

至此,我們說完了疊代器與生成器,總而言之,疊代器就是一個集合,他記錄了資料所在記憶體位址,然後以棧的形式儲存這些記憶體位址,是以python隻需要記住集合的開始位址和偏移量,就可以得到周遊集合,然後根據集合中的每一個記憶體位址就可以得到資料。

生成器就是一個特殊的疊代器,他是一個生成疊代對象的函數,通過yield來生成疊代對象中的每一個元素。