標籤:

Python之Iterable與Iterator

1.Iterable與Iterator介紹

(1)iterable:具體應該叫做可迭代對象。他的特點其實就是我的序列的大小長度已經確定了(list,tuple,dict,string等)。他遵循可迭代的協議。

可迭代協議:

  • 含__iter__()方法。且可迭代對象中的__iter__()方法返回的是一個對應的迭代器。(如list對應的迭代器就是list_iterator)

(2)iterator:具體應該叫做迭代器的對象。他的特點就是他不知道要執行多少次,所以可以理解不知道有多少個元素,每調用一次__next__()方法,就會往下走一步,當然是用__next__()方法只能往下走,不會回退。是惰性的。這樣我可以存很大很大的數據,即使是整個自然數,也可以很輕鬆的用迭代器來表示出來。他滿足的是迭代器協議。

迭代器協議:

  • 含__iter__()方法。且方法返回的Iterator對象本身
  • 含__next__()方法,每當__next__()方法被調用,返回下一個值,直到沒有值可以訪問,這個時候會拋出stopinteration的異常。

2.iterable與Iterator的關係

我們從上面的介紹可以看出。通俗的將就是類中如果滿足可迭代的協議也就是有__iter__()的時候就可以成為可迭代對象。同理如果一個類中有__iter__()和__next__()方法的時候也就可以稱之為迭代器。那他們兩個到底什麼關係呢?

>>> from collections import Iterator, Iterable>>> help(Iterator)Help on class Iterator:class Iterator(Iterable) | Method resolution order: | Iterator | Iterable | builtins.object |**註解:從這裡可以看出Iterable繼承自object, Iterator繼承自Iterable | Methods defined here: | | __iter__(self) | | __next__(self) | Return the next item from the iterator. When exhausted, raise StopIteration......>>> help(Iterable)Help on class Iterable:class Iterable(builtins.object) | Methods defined here: | | __iter__(self)......

從上面的代碼我們很清楚的看出Iterator繼承iterable。這樣我們就很清楚的看到了他們之間的關係了。

那我們說能不能把iterable轉換Iterator呢?當然可以。可以通過iter()函數進行轉換。其實說白了執行iter()方法就是去調用類中的__iter__()方法。其實前面也說了對於iterable如果執行了__iter__()方法他返回的是對應的itertor對象。如果Iterator調用__iter__()方法他返回的就是他自己(也就是一個迭代器)。

iter(iterable)-->iterator

iter(iterator)-->iterator

那我們看看下面這段代碼:

list = [1,2,3,4]list_iterator = iter(list)list.__next__()Traceback (most recent call last): File "G:/Python源碼/iterable_test.py", line 3, in <module> list.__next__()AttributeError: list object has no attribute __next__print(type(list))print(type(list_iterator))<class list><class list_iterator>

我們的list是一個可迭代的對象。可以調用iter(list)說明我們的list中肯定有__iter__()方法。

list_iterator = iter(list)

list的源碼中找到了這個方法。

def __iter__(self, *args, **kwargs): # real signature unknown """ Implement iter(self). """ pass

從下面這段報錯代碼中我們可以看出,list中一定是沒有__next__()方法的。

list.__next__()Traceback (most recent call last): File "G:/Python源碼/iterable_test.py", line 3, in <module> list.__next__()

其實for循環中對於iterable對象有一個轉換。

for x in [1,2,3,4,5]: pass

等價於===>

#先獲取iterator對象it = iter([1,2,3,4,5])while True: try: #獲取下一個值 x = next(it); except StopIteration: # 遇到StopIteration就退出循環 break

3.如何去判斷Iterator和iterable

可以使用isinstance()判斷一個對象是否是Iterable,Iterator對象:

from collections import Iterable,Iteratorlist = [1,2,3,4]list_iterator = iter(list)print(isinstance(list,Iterable),isinstance(list,Iterator))#True Falseprint(isinstance(list_iterator,Iterable),isinstance(list_iterator,Iterator))#True True

從上面我們也可以看出。迭代器(iterator)一定是可迭代對象,但是可迭代對象(iterable)不一定。

4.如何自定義一個迭代器

class EvenIterators(object): def __init__(self,n): self.stop = n self.value = -2 #實現__iter__()方法並返回自身(因為迭代器[實現__iter__和__next__]) def __iter__(self): return self def __next__(self): if self.value+2 > self.stop: raise StopIteration self.value += 2 return self.valuee = EvenIterators(10)print(e.__next__())print(e.__next__())print(e.__next__())print(e.__next__())for en in e: print(en)

上面的EvenIterators類實現了一個偶數迭代器。從這個例子我們可以看出,只要我們實現了迭代協議,即方法__iter__()和next(),我們就實現了iterator。

5.關於迭代問題

那什麼是關於迭代問題呢?我們可以先看一下下面這段代碼:

list = [1,2,3,4]list_iterator = iter(list)for item in list_iterator: print("第一次列印--",item)for item in list_iterator: print("第二次列印--",item)第一次列印-- 1第一次列印-- 2第一次列印-- 3第一次列印-- 4

從上面可以看出,我的迭代器用完了就沒有了。上面使用了第二個for循環沒有列印出什麼東西來,其實如果使用__next__()方法,沒有數據的話也會拋出異常。那我們怎麼去解決這個問題呢?我們可能想到我創建另一個迭代器,然後去遍歷另外一個迭代器。但其實賦值賦給的是地址值,說白了就是他們訪問的是同一塊內存地址。這樣我們就很清楚如何去解決了。因為list中沒有其他的引用類型,所以這個時候使用淺copy和深copy都能解決問題。(當時不能直接使用list_iterator.copy()這種淺複製,因為會拋出沒有這個方法的異常,也就是說iterator中沒有這個copy()方法)

list = [1,2,3,4]list_iterator = iter(list)list_iterator2 = list_iteratorprint(list_iterator.__next__())print(list_iterator2.__next__())print(list_iterator.__next__())print(list_iterator2.__next__())

我們不能對迭代器進行切片淺賦值,也不能直接調用copy方法進行淺複製(因為list中有,但是迭代器中沒有對應的方法)。所以只能使用copy模塊來進行淺複製和深複製。

  1. 淺複製

import copylist = [1,2,3,4]list_iterator = iter(list)list_iterator2 = copy.copy(list_iterator)for item in list_iterator: print(item)for item in list_iterator2: print(item)12341234

  1. 深複製

import copylist = [1,2,3,4]list_iterator = iter(list)copy_list_iterator = copy.deepcopy(list_iterator)for item in list_iterator: print(item)for item in copy_list_iterator: print(item)12341234

推薦閱讀:

用Python實現貝葉斯定理
Python 滲透測試工具集
Python 爬蟲之模擬知乎登錄

TAG:Python |