1. 程式人生 > >迭代與迭代器

迭代與迭代器

迭代

使用for迴圈遍歷取值的過程叫做迭代,比如:使用for迴圈遍歷列表獲取值的過程

for value in [2, 3, 4]:
    print(value)

使用for迴圈遍歷取值的物件叫做可迭代物件, 比如:列表、元組、字典、集合、range、字串

如何判斷物件是否是可迭代物件

from collections import Iterable

# 判斷物件是否是指定型別
result = isinstance((3, 5), Iterable)
print("元組是否是可迭代物件:", result)
結果 :True

result = isinstance([3, 5], Iterable)
print("列表是否是可迭代物件:", result)
結果 :True

result = isinstance(5, Iterable)
print("整數是否是可迭代物件:", result)
結果 :False

如何自定義一個可迭代物件

在類裡面定義__iter__方法建立的物件就是可迭代物件
from collections import Iterable

# 自定義可迭代物件: 在類裡面定義__iter__方法建立的物件就是可迭代物件
class MyList(object):

    def __init__(self):
        self.my_list = list()

    # 新增指定元素
    def append_item(self, item):
        self.my_list.append(item)

    def __iter__(self):
        # 可迭代物件的本質:遍歷可迭代物件的時候其實獲取的是可迭代物件的迭代器, 然後通過迭代器獲取物件中的資料
        pass

my_list = MyList()
my_list.append_item(1)
my_list.append_item(2)
result = isinstance(my_list, Iterable)

print(result)

for value in my_list:
    print(value)
執行結果:
Traceback (most recent call last):
True
  File "/Users/hbin/Desktop/untitled/aa.py", line 24, in <module>
    for value in my_list:
TypeError: iter() returned non-iterator of type 'NoneType'

##通過執行結果可以看出來,遍歷可迭代物件依次獲取資料需要迭代器

迭代器

如下程式碼會介紹到如何自定義迭代器,如何判斷是否是可迭代物件
在類裡面定義__iter__和__next__方法建立的物件就是迭代器物件
iter()函式與next()函式

iter函式: 獲取可迭代物件的迭代器,會呼叫可迭代物件身上的__iter__方法
next函式: 獲取迭代器中下一個值,會呼叫迭代器物件身上的__next__方法

from collections import Iterable, Iterator


# 自定義可迭代物件
class MyList(object):

    def __init__(self):
        # 初始化一個列表
        self.one_list = list()

    def append(self, num):
        self.one_list.append(num)

    # iter函式會調可迭代物件的iter方法
    def __iter__(self):
        my_iterator = MyIterator(self.one_list)
        print(my_iterator)
        # 返回迭代器物件
        return my_iterator


# 自定義迭代器
class MyIterator(object):

    def __init__(self, one_list):

        self.list = one_list
        # 初始化下標
        self.index = 0
        result = isinstance(self, Iterator)
        print("MyIterator建立的物件是否是迭代器:",result)

    def __iter__(self):
        return self

    def __next__(self):

        if self.index < len(self.list):
            self.index += 1
            return self.list[self.index - 1]
        else:
            # 停止迭代
            raise StopIteration


if __name__ == '__main__':

    my_list = MyList()
    my_list.append(1)
    my_list.append(2)

    myDeIterator = iter(my_list)

    # 檢查是否為可迭代物件
    print(isinstance(my_list, Iterable))
    
    #for item in myDeIterator:
    #	 print(item)
    
    while True:
        try:
            # 呼叫迭代器的__next__方法
            print(next(myDeIterator))

        except:
            break

for的本質

遍歷的是可迭代物件

for item in myDeIterator 迴圈的本質就是先通過iter()函式獲取可迭代物件my_list的迭代器,然後對獲取到的迭代器不斷呼叫next()方法來獲取下一個值並將其賦值給item,當遇到StopIteration的異常後迴圈結束。
遍歷的是迭代器

for item in myDeIterator 迴圈的迭代器,不斷呼叫next()方法來獲取下一個值並將其賦值給item,當遇到StopIteration的異常後迴圈結束。

    #for item in myDeIterator:
    #	 print(item)
    
    #for的本質就是while 迴圈不斷呼叫inter()函式和next()函式
    
    while True:
        try:
            # 呼叫迭代器的__next__方法
            print(next(myDeIterator))

        except:
            break

生成器

生成器是一類特殊的迭代器,它不需要再像上面的類一樣寫__iter__()和__next__()方法了, 使用更加方便,它依然可以使用next函式和for迴圈取值

第一種生成器
類似於列表推導式,只是將列表推導式的[ ]改為()
# 列表推導式
my_list = [i * 2 for i in range(5)]
print(my_list)

# 建立生成器
my_generator = (i * 2 for i in range(5))
print(my_generator)

# next獲取生成器下一個值
# value = next(my_generator)
# print(value)

for value in my_generator:
    print(value)
    
 # 執行結果  
[0, 2, 4, 6, 8]
<generator object <genexpr> at 0x101367048>
0
2
4
6
8
第二種生成器
在def函式裡面看到有yield關鍵字那麼就是生成器
def fibonacci(num):
    a = 0
    b = 1
    # 記錄生成fibonacci數字的下標
    current_index = 0
    print("--11---")
    while current_index < num:
        result = a
        a, b = b, a + b
        current_index += 1
        print("--22---")
        # 程式碼執行到yield會暫停,然後把結果返回出去,下次啟動生成器會在暫停的位置繼續往下執行
        yield result
        print("--33---")

fib = fibonacci(5)
value = next(fib)
print(value)
value = next(fib)
print(value)

value = next(fib)
print(value)

# for value in fib:
#     print(value)

# 執行結果
--11---
--22---
0
--33---
--22---
1
--33---
--22---
1