您好,登錄后才能下訂單哦!
小編給大家分享一下Python中可迭代對(duì)象、迭代器是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!
在Python中,有這兩個(gè)概念容易讓人混淆。第一個(gè)是可迭代對(duì)象(Iterable),第二個(gè)是迭代器(Iterator),第三個(gè)是生成器(Generator),這里暫且不談生成器。
可迭代對(duì)象
列表、元組、字符串、字典等都是可迭代對(duì)象,可以使用for循環(huán)遍歷出所有元素的都可以稱為可迭代對(duì)象(Iterable)。在Python的內(nèi)置數(shù)據(jù)結(jié)構(gòu)中定義了Iterable這個(gè)類,在collections.abc模塊中,我們可以用這個(gè)來檢測(cè)是否為可迭代對(duì)象。
>>> from collections import Iterable >>> a = [1,2,3] >>> isinstance(a, Iterable) >>> True >>> b = 'abcd' >>> isinstance(b, Iterable) >>> True
這些數(shù)據(jù)結(jié)構(gòu)之所以能稱之為Iterable,是因?yàn)槠鋬?nèi)部實(shí)現(xiàn)了__iter__()方法,從而可迭代。當(dāng)我們使用for循環(huán)時(shí),解釋器會(huì)調(diào)用內(nèi)置的iter()函數(shù),調(diào)用前首先會(huì)檢查對(duì)象是否實(shí)現(xiàn)了__iter__()方法,如果有就調(diào)用它獲取一個(gè)迭代器(接下來會(huì)講)。加入沒有__iter__()方法,但是實(shí)現(xiàn)了__getitem__()方法,解釋器會(huì)創(chuàng)建一個(gè)迭代器并且按順序獲取元素。如果這兩個(gè)方法都沒有找到,就會(huì)拋出TypeError異常。下面我們自定義對(duì)象,分別實(shí)現(xiàn)這兩個(gè)方法(getitem(), iter())
class MyObj: def __init__(self, iterable): self._iterable = list(iterable) def __getitem__(self, item): return self._iterable[item] obj = MyObj([1,2,3]) for i in obj: print(i)
如上所示,這里沒有實(shí)現(xiàn)__iter__方法,只實(shí)現(xiàn)了__getitem__方法,也使得Myobj稱為可迭代對(duì)象。
下面我們實(shí)現(xiàn)__iter__方法,這里使用了yield語法用來產(chǎn)出值(這里需要生成器的知識(shí))
class MyObj: def __init__(self, iterable): self._iterable = list(iterable) def __iter__(self): index = 0 while True: try: yield self._iterable[index] except IndexError: break index += 1 obj = MyObj([1,2,3]) for i in obj: print(i)
這里同樣讓對(duì)象稱為可迭代對(duì)象。
迭代器
迭代器是一個(gè)可以記住遍歷的位置的對(duì)象。
迭代器對(duì)象從集合的第一個(gè)元素開始訪問,直到所有的元素被訪問完結(jié)束。迭代器只能往前不會(huì)后退。
如上圖所示,迭代器(Iterator)繼承可迭代(Iterable),迭代器必須實(shí)現(xiàn)__iter__方法和__next__方法。其中__next__方法用于產(chǎn)出下一個(gè)元素。
由繼承圖可見,迭代器一定是可迭代對(duì)象,可迭代對(duì)象不一定是迭代器。
迭代器有兩個(gè)基本的方法:iter() 和 next()。
我們使用iter(iterable)即可把可迭代對(duì)象轉(zhuǎn)換成迭代器。
使用next(iterator)來獲取迭代器的下一個(gè)值。
>>> a = [3,4,5] >>> a >>> [3, 4, 5] >>> iter(a) >>> <list_iterator object at 0x10b130ba8> >>> iterator = iter(a) >>> next(iterator) >>> 3 >>> next(iterator) >>> 4 >>> next(iterator) >>> 5 >>> next(iterator) Traceback (most recent call last): File "<input>", line 1, in <module> StopIteration
如上所示,因?yàn)閷?duì)象實(shí)現(xiàn)了__next__方法,我們可以通過next(iterator)來獲取迭代器的下一個(gè)值,直到?jīng)]有值了,拋出StopIteration異常結(jié)束。
迭代器的背后
迭代器Iterator是一個(gè)抽象基類,它定義在_collections_abc.py中
Iterator源碼如下
class Iterator(Iterable): __slots__ = () @abstractmethod def __next__(self): 'Return the next item from the iterator. When exhausted, raise StopIteration' raise StopIteration def __iter__(self): return self @classmethod def __subclasshook__(cls, C): if cls is Iterator: return _check_methods(C, '__iter__', '__next__') return NotImplemented
可以看到,它實(shí)現(xiàn)了__subclasshook__方法,即不用顯式繼承Iterator,只需要實(shí)現(xiàn)__iter__和__next__方法即可稱為Iterator的虛擬子類。這里凸現(xiàn)了Python的鴨子類型,實(shí)現(xiàn)特定的“協(xié)議”即可擁有某種行為。
另外,它自己也定義了__iter__方法,當(dāng)我們使用iter(Iterator)時(shí)直接返回自己,不做任何處理。
iter()函數(shù)的兩個(gè)用法
官方文檔中給出了說明:
iter(iterable) -> iterator iter(callable, sentinel) -> iterator Get an iterator from an object. In the first form, the argument must supply its own iterator, or be a sequence. In the second form, the callable is called until it returns the sentinel.
第一個(gè)用法:iter(iterable) -> iterator (把可迭代對(duì)象轉(zhuǎn)換為迭代器)
第二個(gè)用法:iter(callable, sentinel) -> iterator (第一個(gè)參數(shù):任何可調(diào)用對(duì)象,可以是函數(shù),第二個(gè)是標(biāo)記值,當(dāng)可調(diào)用對(duì)象返回這個(gè)值時(shí),迭代器拋出StopIteration異常,而不產(chǎn)出標(biāo)記值)
>>> from random import choice >>> values = [1,2,3,4,5,6,7] >>> def test_iter(): >>> return choice(values) >>> it = iter(test_iter, 2) >>> it >>> <callable_iterator object at 0x10b130b00> >>> for i in it: >>> print(i) >>> 7 >>> 1 >>> 7 >>> 3 >>> 1
上面代碼的流程:test_iter函數(shù)從values列表中隨機(jī)挑選一個(gè)值并返回,調(diào)用iter(callable, sentinel)函數(shù),把sentinel標(biāo)記值設(shè)置為2,返回一個(gè)callable_iterator實(shí)例,遍歷這個(gè)特殊的迭代器,如果函數(shù)返回標(biāo)記值2,直接拋出異常退出程序。這就是iter函數(shù)的鮮為人知的另一個(gè)用法。
看完了這篇文章,相信你對(duì)Python中可迭代對(duì)象、迭代器是什么有了一定的了解,想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。