Python迭代器與生成器研究記錄
前言
迭代器肯定是可迭代對象,但是可迭代對象不一定是迭代器,生成器一定是迭代器,但是迭代器不一定是生成器
生成器是特殊的迭代器,所以生成器一定是迭代器,迭代器一定是可迭代對象
我們平常接觸最多的對象中,字符串,字典,列表,集合,元組和open打開的文件對象等都是可迭代的對象因為他們都有__iter__()方法,可以遍歷
需要注意的是,我們平常接觸最多的對象中,字符串,字典,列表,集合,元組等都不是迭代器因為他們都沒有__next__()方法,但是open打開的文件對象卻是一個迭代器對象
# obj.__next__()方法 等價于next(obj)
# obj.__iter__()方法 等價于iter(obj)test_list = [10, 20, 30, 40]
generator_obj = (i for i in test_list)
print(generator_obj) # <generator object <genexpr> at 0x0000029852C98C00>
print(generator_obj.__next__()) # 10
print(generator_obj.__iter__()) # <generator object <genexpr> at 0x0000027411078C00>
print(next(generator_obj)) # 20
print(iter(generator_obj)) # <generator object <genexpr> at 0x0000027411078C00>
可迭代對象
1.只要內部有__iter__()方法的對象就是可迭代對象如 字符串,字典,列表集合,元組,包括open打開的文件對象也都是可迭代對象
2.或者可以這樣說,只要可以轉換成迭代器的對象就是可迭代對象
這些都是可迭代對象
test_list = [1, 3, 4, 7]
test_list.__iter__()
test_str = "test_str"
test_str.__iter__()
test_dict = {"1":12}
test_dict.__iter__()
test_set = {"1", "4", "898"}
test_set.__iter__()
with open("file_path", "r") as file_obj:file_obj.__iter__()
可迭代對象調用__iter__()方法會返回一個迭代器,代碼如下
test_list = [1, 3, 4, 7]
print(test_list.__iter__())
print(type(test_list.__iter__()))
# 可迭代對象調用__iter__()方法返回的就是一個迭代器
# <list_iterator object at 0x000001CEB3AD5518>
# <class 'list_iterator'>
迭代器
迭代器就是有__iter__()方法和__next()__方法的對象,所以迭代器肯定是可迭代對象,但是可迭代對象不一定是迭代器
迭代器對象調用__next__()方法每次會拿到迭代器里面的一個值并返回,直到全部拿完會報錯StopIteration
迭代器對象調用__iter__()方法返回的是迭代器本身(和沒調用一樣),可迭代但是非迭代器的對象調用__iter__()方法也是返回的是基于這個對象的迭代器
需要注意的是,我們平常接觸最多的對象中,字符串,字典,列表,集合,元組等都不是迭代器因為他們都沒有__next__()方法,但是open打開的文件對象卻是一個迭代器對象
# 迭代器的一個特征就是有__next__()方法
test_list = [1, 3, 4, 7]
# 可迭代對象調用__iter__()方法返回的就是一個迭代器
list_iterator_obj = test_list.__iter__()# 迭代器調用_next__()方法每次就會拿出這個迭代器里面的一個值,直到全部拿完會報錯
for i in range(5):print(list_iterator_obj.__next__())# 1
# 3
# 4
# 7
# Traceback (most recent call last):
# File "C:/Users/xxx/Desktop/python_test_dir/test_4.py", line 10, in <module>
# print(list_iterator_obj.__next__())
# StopIteration
迭代器對象調用__iter__()方法返回的是他自己,和沒調用一樣
# 迭代器的特征就是有__next__()方法
test_list = [1, 3, 4, 7]
# 可迭代對象調用__iter__()方法返回的就是一個迭代器
list_iterator_obj = test_list.__iter__()# 迭代器對象調用__iter__()方法返回的是他自己,和沒調用一樣
list_iterator_obj2 = list_iterator_obj.__iter__()
print(list_iterator_obj2 is list_iterator_obj) # Trueprint(list_iterator_obj.__next__()) # 1
print(list_iterator_obj.__next__()) # 3
# 注意這里會返回此迭代器對象直接理解為是 list_iterator_obj = list_iterator_obj (因為是返回自己,所以里面剩余的值狀態也是一樣的)
list_iterator_obj = list_iterator_obj.__iter__()
print(list_iterator_obj.__next__()) # 4
print(list_iterator_obj.__next__()) # 7
for 循環遍歷的本質可以理解成
1,每次調用此對象的__iter__()方法返回這個對象的迭代器版本
2,調用第一步返回的此迭代器版本的__next__()方法拿出里面的一個值
3,循環執行第二步直到所有元素拿完for 循環捕獲結束時拋出的StopIteration異常并結束
生成器
生成器可以理解為自己定義的一個迭代器,可以自定義一個生成器,生成器定義有兩種方法
1.函數yield關鍵字返回,含有yield關鍵字的函數會返回一個生成器對象,對此對象調用__next__()方法會執行此函數對應的yield關鍵字之前的代碼并且返回yield關鍵字字后的返回值然后截止,下次調用__next__()方法又可以在上次的基礎上繼續執行
2.生成器表達式(我們以為的"元組推導式"就是生成器表達式,需要注意元組因為是不可變的所以元組沒有推導式,類似元組推導式的形式其實是生成器表達式)
函數yield關鍵字生成器
def test():print("第一次執行")yield 1print("第二次執行")yield 2print("第三次執行")yield 3print("第四次執行")yield 4print("最后一次執行")# test函數返回一個生成器對象
generator_obj = test()print(generator_obj) # <generator object test at 0x000001B393528C00>print(generator_obj.__next__())
# 第一次執行
# 1
print(generator_obj.__next__())
# 第二次執行
# 2
print(generator_obj.__next__())
# 第三次執行
# 3
print(generator_obj.__next__())
# 第四次執行
# 4
print(generator_obj.__next__())
# 最后一次執行
# Traceback (most recent call last):
# File "C:/Users/xxx/Desktop/python_test_dir/test_4.py", line 51, in <module>
# print(generator_obj.__next__())
# StopIteration
生成器表達式
test_list = [10, 20, 30, 40]
generator_obj = (i for i in test_list)
print(generator_obj) # <generator object <genexpr> at 0x0000029852C98C00>
print(generator_obj.__next__()) # 10
print(generator_obj.__next__()) # 20
print(generator_obj.__next__()) # 30
print(generator_obj.__next__()) # 40