解惑python3 可迭代對象(iterable)、迭代器(iteration)、生成器(generator)

 注意:

1.構建可迭代對象和迭代器時經常會出現錯誤,原因是混淆了二者。

(1)可迭代對象有個__iter__( ) 方法,調用該方法每次都實例化一個新的迭代器。

(2)迭代器要實現__next__( )方法返回單個元素,還要實現__iter__( )方法返回本身(self)

因此,迭代器可以迭代,但是可迭代對象不是迭代器!!!

導入模塊:from collections.abc import Iterable,Iterator

可以用 isinstance( x , Iterable ) 判斷x是否爲可迭代對象;

可以用 isinstance( x , Iterator ) 判斷x是否爲迭代器;

 

2.生成器是特殊的迭代器

 

一、可迭代對象 iterable

一句話:“實現了__iter__方法的對象就叫做可迭代對象”

簡單點來說能用for循環進行迭代的對象就是可迭代對象。比如:字符串、列表、元組、集合...

注意:

1.調用可迭代對象的__iter__() 方法返回一個可迭代對象(iterable)

2.不斷調用迭代器的__next__() 方法返回元素

3.直到迭代完成後,處理StopIteration異常

>>> a = [1,2,3]
>>> b = a.__iter__()
>>> print(b)
<list_iterator object at 0x000001E9C5781860>
>>> b.__next__()
1
>>> b.__next__()
2
>>> b.__next__()
3
>>> b.__next__()
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    b.__next__()
StopIteration

 

 二、迭代器 iterator

什麼叫迭代器?它就是一個帶狀態的對象,他能在你調用 next() 方法的時候返回容器中的下一個值。

任何實現了__iter____next__()方法的對象都是迭代器。

標準的迭代器接口有兩個方法:

(1)__next__( ) :返回下一個可用的元素,如果沒有元素,拋出StopIteration異常。

(2)__iter__( ) :返回self,以便在應該使用可迭代對象的地方使用迭代器,比如for循環中。

迭代器就像一個懶加載的工廠,等到有人需要的時候纔給它生成值返回,沒調用的時候就處於休眠狀態等待下一次調用。直到無元素可調用,返回StopIteration異常。

例子如下實現斐波那契數列:

>>> class Fib():
	def __init__(self,max):
		self.n = 0
		self.prev = 0
		self.curr = 1
		self.max = max
	def __iter__(self):
		return self
	def __next__(self):
		if self.n<self.max:
			value = self.curr
			self.curr += self.prev
			self.prev = value
			self.n += 1
			return value
		else:
			raise StopIteration

		
>>> f = Fib(5)
>>> next(f)
1
>>> f.__next__()
1
>>> next(f)
2
>>> next(f)
3
>>> next(f)
5
>>> next(f)
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    next(f)
  File "<pyshell#25>", line 17, in __next__
    raise StopIteration
StopIteration

 

三、生成器 generator

注意:生成器是特殊的迭代器(反之不成立),不需要寫__iter__( )、__next__( ),只需要一個yield關鍵字。

在Python中,這種一邊循環一邊計算的機制,稱爲生成器:generator

使用next()函數和send()函數恢復生成器

(1)next()函數:next的作用是喚醒並繼續執行

(2)send()函數:send的作用是喚醒並繼續執行,發送一個信息到生成器內部

生成器類似於返回值爲數組的一個函數,這個函數可以接受參數,可以被調用,但是,不同於一般的函數會一次性返回包括了所有數值的數組,生成器一次只能產生一個值,這樣消耗的內存數量將大大減小,而且允許調用函數可以很快的處理前幾個返回值,因此生成器看起來像是一個函數,但是表現得卻像是迭代器.

python提供了兩種基本的方式:

(1)生成器函數:用def 定義的利用關鍵字yield一次性返回一個結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次從它離開的地方繼續執行。如下:

# 例子1:斐波那契數列

def Fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return '啊哈沒有數據了喔'


f = Fib(10)
# 使用一個循環捕獲最後return 返回的值,保存在異常StopIteration的value中
while 1:
    try:
        x = next(f)
        print('f:', x)
    except StopIteration as e:
        print('生成器最後返回的值:', e.value)
        break


# 例子2:

def foo():
    print("first")
    count=yield
    print(count)
    yield

f = foo()   
f.send(None)
f.send(2)

"""
例子2解釋:
f = foo() 返回一個生成器
f.send(None) 進行函數執行代碼,遇到count = yield,凍結並跳出函數體
f.send(2) 再次進入函數體,接着凍結的代碼繼續執行,把2傳給變量count,
          打印count,遇到yield凍結並跳出函數
"""

(2)生成器表達式:生成器表達式是列表推導式的生成器版本,看起來像列表推導式,但是它返回的是一個生成器對象而不是列表對象。

from collections.abc import Iterable,Iterator
a = (x for x in range(10))
print(isinstance(a,Iterable))  # True
print(isinstance(a,Iterator))  # True

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章