1. 程式人生 > >python3:深刻理解__iter__和__next__ 迭代器的原理(用自定義迭代器方法進行講解)

python3:深刻理解__iter__和__next__ 迭代器的原理(用自定義迭代器方法進行講解)

1.iter 的用法

咱都知道, list ,tuple,dict 都是可迭代物件,如果想讓他們轉化成迭代器.
我們可以這麼做,呼叫 inter()方法,它會返回一個迭代器.
例如:

from collections import Iterable,Iterator

a=[1,2]
b=(1,)
c={"name":"Andy"}

print(type(a),type(b),type(c))   #<class 'list'> <class 'tuple'> <class 'dict'>

print(isinstance(a,Iterable),isinstance(b,Iterable),isinstance(c,Iterable))  #True True True
print(isinstance(a,Iterator),isinstance(b,Iterator),isinstance(c,Iterator)) #False False False
a_iterator=iter(a)
b_iterator=iter(b)
c_iterator=iter(c)

print(isinstance(a_iterator,Iterable),isinstance(b_iterator,Iterable),isinstance(c_iterator,Iterable)) #True True True

2.getitem 也是模擬的返回一個迭代器

前面我講過 getitem 這個魔法函式,它可以改變物件型別變成一個iterable ,也就是迭代器

例如:

class Person:
    def __init__(self,persion_list):
        self.persion_list=persion_list
    def __getitem__(self, item):
        return self.persion_list[item]
 
body=Person(["Xiuwu","Adny","Maggie"])

for i in body:
    print (i)

上邊的程式碼我們用for迴圈的時候, 實際上就用了iter()方法 ,不理解可以看看我的上篇寫作.

然後看下如下程式碼

class Person:
    def __init__(self, persion_list):
        self.persion_list = persion_list
    def __iter__(self):
        return  1
    def __getitem__(self, item):
        return self.persion_list[item]


body = Person(["Xiuwu", "Adny", "Maggie"])

body=iter(body)

列印結果:

 iter() returned non-iterator of type 'int'

1.說明 用iter(body)的時候首先找到 ——iter__方法,由於我們返回的不是的個iterator所以報錯,
2. __iter__方法找不到,它會繼續找 是否有模擬返回迭代器呢,
3. 如果你把__iter__登出掉,它會找到——getitem——

咱們測試下,是否getitem 是否實現iterable ,程式碼如下:

from collections import Iterable, Iterator


class Person:
    def __init__(self, persion_list):
        self.persion_list = persion_list
    #def __iter__(self):
     #   return  1
    def __getitem__(self, item):
        return self.persion_list[item]


body = Person(["Xiuwu", "Adny", "Maggie"])

print(iter(body))     #<iterator object at 0x0000000002242AC8>
print(isinstance(iter(body),Iterator) #True     說明getitem是可以轉化為iterable

如果把getitem 也登出,按道理應該body 不是iterable了,試試
登出之後再執行報錯如下:

TypeError: 'Person' object is not iterable

證明咱們的想法是對的.

3.分析原理後,咱們就自己寫個迭代器.

前面我們已經知道了,迭代器需要重寫兩個方法,如下:

class Myiterator:
    def __iter__(self):
        pass
    def __next__(self):
        pass 

如果繼承了 Iterator類 ,iter 方法 可以刪除.如下:

class Myiterator(Iterator):
    def __next__(self):
        pass 

這個__next__ 正是我們要重寫的取值邏輯

完成的程式碼如下,解釋請看備註:

from collections import Iterable, Iterator

class Person:
    def __init__(self, persion_list):
        self.persion_list = persion_list
    def __iter__(self):
        return  Myiterator(self.persion_list)   #呼叫我們重寫的迭代器方法
    #def __iter__(self):
     #   return  1
    #def __getitem__(self, item):   #把這個方法用我們自己寫的迭代器方法替代.
     #   return self.persion_list[item]  
class Myiterator(Iterator):         #繼承Iterator 就不需要寫__iter__,直接呼叫父類的.
    def __init__(self,persion_list):
        self.persion_list=persion_list  
        self.index=0      #由於iterator 是沒有index 的,這個要我們手動新增
    def __next__(self):   #這個就是迭代器的取值邏輯 
        while True:      #當為false 的時候結束迴圈
            try:
                word = self.persion_list[self.index]      #取值動作 
            except IndexError:   #index 當變得超出persion_list 會報錯的 ,先抓住這個異常
                raise StopIteration     #迭代到沒有值要用這異常,咱們把異常做個轉化 
            self.index = self.index + 1   #遞增我們的index
            return word   #返回取到的值


body = Person(["Xiuwu", "Adny", "Maggie"])

a=iter(body)    #呼叫我們自定義的迭代器方法 
 print(a)   # <__main__.Myiterator object at 0x00000000022399B0>  
               #從列印結果看說明我們自定義的迭代器方法生效了,已經返回一個迭代器

print(next(a))  #Xiuwu  
                       #從列印結果我們判斷出 __next__生效,如果想迴圈輸出,自己試試for 迴圈.