python奇遇記:迭代器和生成器

來講說迭代器和生成器,還有可迭代對象和生成器表達式。python

以前簡單的提到過,一個對象是可迭代的能夠理解爲可以使用for循環。這樣說其實不太準確,某個對象可迭代是由於它內部實現了$__iter__$這個特殊方法。好比在python中,序列類型(列表,元組這些)都是能夠迭代的,由於內部都有$__iter__$方法的實現。數據結構

不過,其實咱們不用特別的實現$__iter__$方法,只要實現了$__getitem__$方法就能夠。這個方法我以前介紹過,實現它以後就能夠進行切片以及迭代操做。爲何?由於在對一個對象迭代時若是找不到$__iter__$方法,python會自動去尋找$__getitem__$方法,而後構造一個迭代器,從0開始獲取元素。機器學習

說了半天,迭代器又是什麼東西?可迭代對象,迭代器,這兩個是同樣的嗎?函數

迭代器是實現了$__next__$特殊方法的對象,而可迭代對象實現了$__iter__$方法,若是你須要迭代器可以迭代自身,也須要實現$__iter__$方法。要注意的是,可迭代的對象必須實現$__iter__$方法,但不能實現 $__next__$ 方法。學習

在迭代器中實現了$__next__$方法,你就能使用next(data)來依次產出數據,若是此時沒有數據了,就會產生異常。像生孩子同樣,next一下生一個。spa

有點繞是否是,其實,通常只要知道可迭代對象以及它是如何實現的就好了,python 中經常用生成器來代替迭代器,能夠說,生成器就是迭代器。由於生成器也實現了$__iter__$和$__next__$方法。設計

python中還有一個iter函數用來生成迭代器,好比把一個列表放進去,就可使用next方法來一個個調用了。code

說了這麼多,來看個例子。對象

data = [1, 2, 3, 4]

# data是列表,是個可迭代對象
# 使用循環迭代
for i, j in enumerate(data):
    print(i, j)

# 生成一個迭代器
d = iter(data)
# 調用next
next(d)
# 調用四次以後就會產生異常
0 1
1 2
2 3
3 4





1

咱們來本身實現一個迭代器。圖片

# 從後往前產出列表中的數據
class ReverseList:

    def __init__(self, item):
       #用range構造一個列表
        self.list = list(range(item))

    def __iter__(self):
        return self

    def __next__(self):

        try:
            return self.list.pop()
        except:
            raise StopIteration

用一下試試。

data = ReverseList(4)

# 調用next,從後往前產出數據
print(next(data))
print(next(data))
print(next(data))
print(next(data))
# 若是繼續調用,會產生錯誤,由於沒有數據可產出了
print(next(data))
3
2
1
0



---------------------------------------------------------------------------

IndexError                                Traceback (most recent call last)

<ipython-input-30-cfc36c66205d> in __next__(self)
     12         try:
---> 13             return self.list.pop()
     14         except:


IndexError: pop from empty list


During handling of the above exception, another exception occurred:


StopIteration                             Traceback (most recent call last)

<ipython-input-35-1dd792231191> in <module>()
      7 print(next(data))
      8 # 若是繼續調用,會產生錯誤,由於沒有數據可產出了
----> 9 print(next(data))


<ipython-input-30-cfc36c66205d> in __next__(self)
     13             return self.list.pop()
     14         except:
---> 15             raise StopIteration


StopIteration:

那什麼又是生成器?

在程序設計中,內存是個很寶貴的東西,佔用太多的內存老是很差的,生成器的做用就是我先把你的數據表示出來,可是實際上並不佔用內存空間,只有在你調用它時纔會佔用。通常狀況下,好比你定義了一個列表,會自動的使用一段內存空間。

在 python中,只要定義了yield關鍵字的函數就是生成器。上面說了,生成器就是迭代器,你能夠進行迭代操做(循環),調用next來一個個產出數據。

def gen123():
    yield 1
    yield 2
    yield 3

for i in gen123():
    print(i)

g = gen123()
print(next(g))
1
2
3
1

雖說生成器就是迭代器,可是在python的定義中,迭代器用來遍歷集合,從中產出元素,而生成器無需遍歷集合就能生成值,好比range()函數,生成器不只可以產出集合中的元素,還能夠產出派生自元素的其餘值。

我在上一篇文章(Python奇遇記:數據結構窺探2)中提到過生成器表達式,只介紹了一下它的用法,那麼生成器表達式是什麼東西?

其實,生成器表達式就是生成器的快速實現而已,相似於以前講過的具名元組。有些時候須要快速的生成一段數據,使用生成器表達式便可,無需定義函數再調用。


本人才疏學淺,上文中不免有些錯誤,還請各位品評指正。若是以爲寫的還行,歡迎關注個人公衆號MLGroup,帶你走進機器學習的世界。
圖片描述

相關文章
相關標籤/搜索