python3_迭代器與生成器__ / __iter__() / __next__() / yield / next() / iter()
1. 可用於for迴圈的資料型別有一下幾種:
(1)集合資料型別:list, tuple, dict, set, str, bytes
(2)generator(資料結構):生成器、帶yield的generator function
2. 可迭代物件(iterable):可直接作為for迴圈的物件,統稱為可迭代物件。python從可迭代物件中獲取迭代器。但凡是可以返回一個迭代器的物件都可稱之為可迭代物件。
3. 生成器都是迭代器,迭代器不一定是生成器
1.迭代器
1. 迭代器:可以被next()函式呼叫並不斷返回下一個值的物件稱為迭代器
2. 迭代器物件從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會後退。
3. 迭代器有兩個基本的方法:iter() 和 next()。
4. 可使用isinstance()判斷一個物件是否是迭代器物件(Iterator)
5. Python3中range(n)生成的是迭代器物件; python2中xrange(n)生成的才是迭代器物件
(a)iter()通過資料結構建立迭代器
1. 字串,列表,元組,集合物件都可用於建立迭代器
import sys str = "hello str" lt = [1, 2, 3] tp = (11, 22, 33) st = set([111, 222, 333]) str_iter = iter(str) print(next(str_iter)) print(next(str_iter)) print("*" * 100) lt_iter = iter(lt) print(next(lt_iter)) print(next(lt_iter)) print("*" * 100) tp_iter = iter(tp) print(next(tp_iter)) print(next(tp_iter)) print("*" * 100) set_iter = iter(st) set_iter = iter(st) while True: try: print(next(set_iter)) # StopIteration 異常用於標識迭代的完成,防止出現無限迴圈的情況,在 __next__() 方法中我們可以設定在完成指定迴圈次數後觸發 StopIteration 異常來結束迭代。 except StopIteration as st: sys.exit(st.value)
(b)將類(class)改造成迭代器
1. 把一個類作為一個迭代器使用需要在類中實現兩個方法 __iter__() 與 __next__() 。
2. __iter__() 方法返回一個特殊的迭代器物件, 這個迭代器物件實現了 __next__() 方法並通過 StopIteration 異常標識迭代的完成。
3. __next__() 方法(Python 2 裡是 next())會返回下一個迭代器物件。
# 類迭代器
# 必須在類內部實現 __iter__() / __next__()兩個方法
class Eg2(object):
"""
可迭代物件:從python內部獲取迭代器
"""
def __init__(self, text):
# type:list
self.sub_text = text.split(" ")
def __iter__(self):
return Eg2Iterator(self.sub_text)
class Eg2Iterator:
"""
迭代器:對已經劃分完畢的字串進行迭代
"""
def __init__(self, sub_text):
self.sub_text = sub_text
self.index = 0
def __next__(self):
try:
subtext = self.sub_text[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return subtext
def __iter__(self):
return self
if "__main__" == __name__:
o2 = Eg2("hello, the wonderful new world!")
for i in o2:
print(i, end=" | ")
(c)方法或函式改造成迭代器(生成器為特殊的迭代器)
此處不做詳細說明。具體改造如下:
class Eg2(object):
def __init__(self, text):
# type:list
self.sub_text = text.split(" ")
def __iter__(self):
# 以下三種方式均可
for item in self.sub_text:
yield item
# yield from self.sub_text
# return (item for item in self.sub_text)
if "__main__" == __name__:
o2 = Eg2("hello, the wonderful new world!")
for i in o2:
print(i, end=" | ")
2.生成器
1. inspect模組中isgeneratorfunction()能夠判斷一個函式是否為生成器函式
(a)生成器的定義與使用
1. 在Python中使用了yield的函式稱為生成器
2. 什麼時候使用yield: 一個函式 f,f 返回一個 list,這個 list 是動態計算出來的(不管是數學上的計算還是邏輯上的讀取格式化),並且這個 list 會很大(無論是固定很大還是隨著輸入引數的增大而增大),這個時候,我們希望每次呼叫這個函式並使用迭代器進行迴圈的時候一個一個的得到每個 list 元素而不是直接得到一個完整的 list 來節省記憶體,這個時候 yield 就很有用。
3. 生成器其實是一種特殊的迭代器,不過這種迭代器更加優雅。僅需要一個yield關鍵字。
4. 任何生成器也是以一種懶載入的模式生成值。
5. 生成器相比其它容器物件它更能節省記憶體和CPU。執行一次運算一次。
6. 生成器中的元素第一之後並不實際生成。
7. 在一個 generator function 中,如果沒有 return,則預設執行至函式完畢,如果在執行過程中 return,則直接丟擲 StopIteration 終止迭代。
# 4.生成器
def fibonacci(n):
a = 0
b = 1
count = 0
while count < n:
yield b
a, b = b, a+b
count += 1
# StopIteration.value
return "--這是異常時列印的資訊--"
if "__main__" == __name__:
# a = fibonacci(10)
# for i in range(10):
# print(a.__next__())
g = fibonacci(5)
while True:
try:
# def next(iterator, default=None)
# 當迭代器遍歷完畢後,x預設列印值為default
x = next(g)
print("g: ", x)
except StopIteration as e:
print("Generator return value: ", e.value)
break
(b)生成器表示式
1. 生成器表示式是列表推倒式的生成器版本,看起來像列表推導式,但是它返回的是一個生成器物件而不是列表物件。
# 生成器表示式
# 生成器表示式是列表推倒式的生成器版本,看起來像列表推導式,但是它返回的是一個生成器物件而不是列表物件。
a = [i for i in range(10)]
b = (i for i in range(10))
print("sum(a): ", sum(a),", sum(b): ", sum(b))
print(type(a)) # <class 'list'>
print(type(b)) # <class 'generator'>
3.yield的使用解析
python3_生成器__yield 使用淺析