迭代器、生成器和可迭代對象

前言

上次我們簡單分享了迭代器和生成器,本次我們來更加深入的瞭解相關概念和使用方法,希望能對你有所幫助。

自定義迭代器

首先,我們來看看怎麼自定義迭代器,自定義迭代器的類需要下面幾個組成。

(1)類中需要定義iter和next魔術方法。
(2)iter魔術方法返回對象本身。
(3)next方法返回下一個數據,如果沒有數據,就報異常StopIteration。

class Test:

    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration
        return self.counter


t = Test()
print(next(t))
print(next(t))
print(next(t))

1
2
StopIteration

當然,我們可以直接使用for循環來調用這個迭代器對象。

 for i in t:
     print(i)

1
2

for循環裏面到底是怎麼執行的了?首先for循環會先調用對象的iter魔術方法,返回一個迭代器對象,然後不斷調用next魔術方法(異常就停止循環)。

生成器

我們之前學習過,函數中有yield關鍵字,那這個函數就是生成器。

def func():
    yield 1
    yield 2


f = func()
print(next(f))
print(next(f))

1
2

其實這個生成器對象內部其實是調用的生成器類generator創建的對象,生成器類的內部其實也聲明瞭iter和next魔術方法。

生成器也完全符合迭代器聲明的規則,所以,生成器也是一種特殊的迭代器。

可迭代對象

最後,我們再聊聊可迭代對象,我們都知道,列表就是可迭代對象。

l = [1, 2, 3]
for i in l:
    print(i)

字符串,字典等等能夠循環的,都是可迭代對象。其定義是,如果類中有iter魔術方法,並且返回的是迭代器對象,那這個類創建的對象就是可迭代對象。

class Test:

    def __init__(self):
        self.counter = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == 3:
            raise StopIteration
        return self.counter


class Foo:
    def __iter__(self):
        return Test()


foo = Foo()
for item in foo:
    print(item)

1
2

這裏的foo就是可迭代對象,當使用for循環時,先調用iter魔術方法,返回一個迭代器對象,接着就是不斷的調用next魔術方法返回值。

我們可以驗證下,列表是可迭代對象,那他就應該有iter方法,沒有next方法。

l = [1, 2, 3]
print(dir(l))

#['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
print(dir(l.__iter__()))

調用iter方法後,就會有iter和next方法了。

自定義range函數

學了這麼多,我們來自定義一個range函數來鞏固下學習內容。

class RangeIter:

    def __init__(self, num):
        self.num = num
        self.counter = -1

    def __iter__(self):
        return self

    def __next__(self):
        self.counter += 1
        if self.counter == self.num:
            raise StopIteration
        return self.counter


class Xrange:

    def __init__(self, maxnum):
        self.maxnum = maxnum

    def __iter__(self):
        return RangeIter(self.maxnum)

    
for i in Xrange(10):
    print(i)

生成器也可以實現該功能。

class Xrange:

    def __init__(self, maxnum):
        self.maxnum = maxnum

    def __iter__(self):
        counter = 0
        while counter < self.maxnum:
            yield counter
            counter += 1

for i in Xrange(5):
    print(i)

今天的分享就到這了,我們下期再見~

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