1. 程式人生 > >【Python】迭代器(iterator) vs 生成器(generator)

【Python】迭代器(iterator) vs 生成器(generator)

迭代器(iterator)

在介紹迭代器之前還有一種iterable物件需要簡單的說明。對於iterator和iterable是兩個不同的概念。

iterable

  • iterable是含有__iter__方法或者__getitem__ 的一個物件,當你想實現一個iterable物件的時候,通過實現__iter__方法返回一個iterator而不是iterable。檢查一個物件是不是iterable物件一般是通過catch異常的方式去檢查,雖然這個方式有點挫;另外一種是檢查是否是容器類中的Itreaable物件if isinstance(e, collections.Iterable)。對於一個iterable的物件可以通過呼叫iter方法返回一個iterator物件,然後進行for loop訪問。
class Iterable_:
   def __iter__(self):
       return iter([1, 2, 3]) 
it = iter((Iterable_()))
for i in it: 
    print "iterable:" + str(i)

#輸出
iterable:1
iterable:2
iterable:3

iterator

  • 迭代器肯定是iterable型別的物件,它是包含有next(Python 2)方法或者__next__(Python 3)方法和__iter__(返回self)方法的一個特殊物件,可以對這樣一個物件進行for loop迴圈訪問。
  • 對於實現next方法需要注意的是,當沒有下一個元素的時候必須丟擲StopIteration異常
  • 當遍歷一個迭代器的時候,它會修改內部狀態,導致你只能向前獲取下一個元素,不能通過迭代器訪問後面一個元素;也就是說當你通過迭代器訪問了一個元素以後,在當前迴圈中不能後退繼續訪問該元素了,除非你重新生產迭代器物件進行遍歷。
  • 另外需要注意的是在迭代器中next方法是return下一個元素的值,不像下面介紹的生成器yield一個元素。
class Iterator_:
   def __init__(self, s, e): 
       self.current = s 
       self.end = e 
   def __iter__(self):
       return self
   def next(self):
       if self.current < self.end:
           self.index = self.current
           self.current += 1
           return self.index
       else:
           raise StopIteration
it = Iterator_(5, 8)
for i in it: 
    print "iterator:" + str(i)
#never print
for i in it: 
    print "second iterator:" + str(i)
#print again
it = Iterator_(5, 8)
for i in it: 
    print "second iterator:" + str(i)
#輸出
iterator:5
iterator:6
iterator:7
second iterator:5
second iterator:6
second iterator:7

生成器(generator)

對於一個生成器它一定是一個迭代器,可以通過for loop進行訪問其中的元素,但是一個迭代器卻很明顯的不一定是生成器 定義迭代器有兩種方式,第一個是使用yield關鍵詞,另外一個是生成器表示式"()"。對於一個方法在方法體裡加上yield關鍵詞就變成了生成器。yield作用就是返回一個生成器,它會儲存當前函式狀態,記錄下一次函式被呼叫next的時候執行狀態。當函式沒有下一次執行狀態的時候,再繼續呼叫next方法,這個時候StopIteration異常就被丟擲。
print "generator"
#first way 
my_generator = (x for x in range(3))
for i in my_generator:
    print i
#second way
def Generator_(l):
   n = 0 
   size = len(l)
   while n < size:
       yield l[n]   
       n += 1

ge = Generator_([1, 2, 3]) 
for g in ge: 
    print "generator:" + str(g)

因為生成器是一個迭代器,所以迭代器具有的特性,生成器肯定會具有的。比如只能向前遍歷等。當然除了迭代器特性之外,生成器還有自己的方法。比如send方法等。通過send可以定義當前生成器中的值。