亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

python學習之可迭代對象、迭代器、生成器

瀏覽:2日期:2022-06-23 13:10:10
Iterable ? 可迭代對象

能夠逐一返回其成員項的對象。 可迭代對象的例子包括所有序列類型 (例如 list, str 和 tuple) 以及某些非序列類型例如 dict, 文件對象以及定義了__iter__()方法或是實現了序列語義的__getitem__() 方法的任意自定義類對象。

可迭代對象可用于 for 循環以及許多其他需要一個序列的地方(zip()、map() …)。當一個可迭代對象作為參數傳給內置函數 iter() 時,它會返回該對象的迭代器。這種迭代器適用于對值集合的一次性遍歷。在使用可迭代對象時,你通常不需要調用 iter() 或者自己處理迭代器對象。for 語句會為你自動處理那些操作,創建一個臨時的未命名變量用來在循環期間保存迭代器

判斷對象是否為可迭代對象:可以使用isinstance與collections模塊的Iterable類型

#分別對python的各種數據類型進行判斷from collections import Iterablea = 123isinstance(a,Iterable) >>> Falsea = ’abc’isinstance(a,Iterable) >>> Truea = (1,2,3)isinstance(a,Iterable) >>> Truea = [1,2,3]isinstance(a,Iterable) >>> Truea = {’name’:’wwl’,’age’:24,’sex’:’男’}isinstance(a,Iterable) >>> Truea = {1,2,3}isinstance(a,Iterable) >>> True#可以看到字符串,元組,列表,字典,集合是可迭代對象;數字不是

通過上面我們得到可迭代對象有:字符串,元組,列表,字典,集合我們可以使用內置的dir()函數對python數據類型進行操作,會發現可迭代對象(str,tuple,list,dict,set)均實現了__iter__方法,而不是可迭代對象的int類型則沒有__iter__方法

dir(int)[’...(省略)’, ’__index__’, ’__init__’, ’__init_subclass__’, ’__int__’, ’__invert__’,’...(省略)’ ]dir(str)[’...(省略)’, ’__iter__’, ’...(省略)’]dir(tuple)[’...(省略)’, ’__iter__’, ’...(省略)’]dir(list)[’...(省略)’, ’__iter__’, ’...(省略)’]dir(dict)[’...(省略)’, ’__iter__’, ’...(省略)’]dir(set)[’...(省略)’, ’__iter__’, ’...(省略)’]

到底是不是__iter__方法決定對象是否是可迭代對象呢?我們可以驗證一下:

#自定義兩個類:A類和B類,其中B類實現__iter__方法,A類則沒有from collections import Iterableclass A():... def __init__(self):... pass... class B(): def __init__(self): pass def __iter__(self): return self#生成兩個實例化對象:a和b a = A()b = B()#可以看到實現__iter__方法的b對象是可迭代對象,而a對象不是isinstance(a,Iterable) >>> Falseisinstance(b,Iterable) >>> True特殊情況:實現了__getitem__方法的序列也是可迭代對象

sequence ? 序列一種 iterable,它支持通過__getitem__() 特殊方法來使用整數索引進行高效的元素訪問,并定義了一個返回序列長度的__len__() 方法。內置的序列類型有list、str、tuple 和 bytes。注意雖然 dict 也支持__getitem__() 和__len__(),但它被認為屬于映射而非序列,因為它查找時使用任意的 immutable 鍵而非整數。

#自定義一個實現__getitem__方法的序列class A(): def __init__(self,*args): self.args = args def __getitem__(self,i): return self.args[i] def __len__(self): num = 0 while True: try: self.args[num] num += 1 except: return num a = A(1,2,3,’ss’,’dd’)#可以看到實例化后的對象是可以通過for...in進行循環訪問的,表示其是可迭代對象。for i in range(len(a)): print(a[i]) >>> 1 2 3 ss dd #我們使用collections模塊的Iterable進行判斷:from collections import Iterable,Iteratorisinstance(a,Iterable) >>> False#結果出乎意料,判定對象a不是可迭代對象,為什么呢?#因為collections模塊的Iterable自動忽略了對象的__getitem__方法,只根據對象是否有__iter__方法進行判斷。一般來說,標準的序列均實現了__iter__方法。#既然上面方法無法判斷具有__getitem__方法的序列是否是可迭代對象,那又該如何判斷呢?#可以使用iter()函數,如果不報錯,說明是可迭代對象,報錯就不是b = iter(a)isinstance(b,Iterable) >>> Trueisinstance(b,Iterator) >>> TrueIterator ? 迭代器:內部實現__iter__和__next__方法的對象

用來表示一連串數據流的對象。重復調用迭代器的 next() 方法(或將其傳給內置函數 next())將逐個返回流中的項。當沒有數據可用時則將引發 StopIteration 異常。到這時迭代器對象中的數據項已耗盡,繼續調用其 next() 方法只會再次引發 StopIteration 異常。迭代器必須具有 iter() 方法用來返回該迭代器對象自身,因此迭代器必定也是可迭代對象,可被用于其他可迭代對象適用的大部分場合。一個顯著的例外是那些會多次重復訪問迭代項的代碼。容器對象(例如 list)在你每次向其傳入 iter() 函數或是在 for 循環中使用它時都會產生一個新的迭代器。如果在此情況下你嘗試用迭代器則會返回在之前迭代過程中被耗盡的同一迭代器對象,使其看起來就像是一個空容器。

判斷對象是否為迭代器:使用isinstance與collections模塊的Iterator類型

from collections import Iterable,Iterator#創建兩個類:B類和C類,B類實現了__iter__方法,C類實現了__iter__和__next__方法class B(): def __init__(self): pass def __iter__(self): return self class C(): def __init__(self): pass def __iter__(self): return self def __next__(self): return 123#實例化兩個對象 b = B()c = C()#可以看到b對象是可迭代對象,卻不是迭代器;c對象既是可迭代對象,又是迭代器.isinstance(b,Iterable) >>> Trueisinstance(b,Iterator) >>> Falseisinstance(c,Iterator) >>> Trueisinstance(c,Iterable) >>> True生成迭代器有兩種方法:1.使用內置的iter(object[, sentinel])函數;

返回迭代器對象。根據第二個參數的存在,第一個參數的解釋非常不同。如果沒有第二個參數,對象必須是支持迭代協議的集合對象(iter()方法),或者必須支持序列協議(getitem()方法,整數參數從0開始)。如果它不支持這兩個協議中的任何一個,則會引發TypeError。如果給出了第二個參數sentinel,那么object必須是可調用的對象。在這種情況下創建的迭代器將調用對象,每次調用它的__next __()方法時都不帶參數;如果返回的值等于sentinel,則將引發StopIteration,否則將返回該值。

iter()的第一種形式:不帶第二個參數,第一個參數表示可迭代對象(具有__iter__()方法或者__getitem__()方法)

#自定義兩個類,一個支持__iter__()方法,一個支持__getitem__()方法#1.定義一個支持迭代協議的集合對象:class A(): def __init__(self): pass def __iter__(self): self.num = 0 return self def __next__(self): if self.num < 10: N = self.num self.num += 1 return N else: raise StopIteration a = A()b = iter(a)from collections import Iterable,Iterator#由于A類中我們定義的__iter__()函數是返回自己,同時定義了自身的__next__()方法,所以對象a既是可迭代對象,又是迭代器。isinstance(a,Iterable) >>> Trueisinstance(a,Iterator) >>> True#同時我們可以看到對象a經過iter()方法后生成的b對象是迭代器。isinstance(b,Iterator) >>> Trueisinstance(b,Iterable) >>> True#定義一個支持序列協議的對象class B(): def __init__(self,*args): self.args = args def __getitem__(self,i): return self.args[i] def __len__(self): num = 0 while True: try: self.args[num] num += 1 except: return numb = B()c = iter(b)#由于b對象定義的是__getitem__()方法,所以無法使用collections模塊對b對象進行判斷。#這里我們只對使用了iter()方法后生成的c對象進行判斷isinstance(c,Iterable) >>> Trueisinstance(c,Iterator) >>> True#可以看到使用了iter()方法后生成的對象c是迭代器

iter()的第二種形式:帶第二個參數,第一個參數表示可調用對象,當返回值為第二個參數時,觸發StopIteration

class A(): def __init__(self): self.num = 1 def __call__(self): x = self.num self.num += 1 return x a = A()b = iter(a,5)from collections import Iterable,Iterator#我們可以看到a對象既不是可迭代對象也不是迭代器,但通過iter()方法返回的對象b確實迭代器isinstance(a,Iterable) >>> Falseisinstance(a,Iterator) >>> Falseisinstance(b,Iterator) >>> Trueisinstance(b,Iterable) >>> True#通過for...in循環遍歷打印(每次循環都調用__call__()方法,直至返回值等于5,觸發StopIteration停止迭代)for i in b: print(i) >>> 1 2 3 4 #iter()的第二種形式的一個有用的應用是構建塊讀取器。例如,從二進制數據庫文件中讀取固定寬度的塊,直到到達文件結尾:from functools import partialwith open(’mydata.db’, ’rb’) as f: for block in iter(partial(f.read, 64), b’’): process_block(block)2.直接調用可迭代對象的__iter__方法;

#定義__iter__()方法,可以返回自己,但自己要定義__next__()方法;也可以返回其他對象的迭代器#第一種:返回自身,同時定義自身的__next__()方法class A(): def __init__(self): pass def __iter__(self): self.num = 0 return self def __next__(self): if self.num < 10: N = self.num self.num += 1 return N else: raise StopIterationa = A()b = a.__iter__()from collections import Iterable,Iterator#由于A類中我們定義的__iter__()函數是返回自己,同時定義了自身的__next__()方法,所以對象a既是可迭代對象,又是迭代器。isinstance(a,Iterable) >>> Trueisinstance(a,Iterator) >>> True#同時我們可以看到對象a經過iter()方法后生成的b對象是迭代器。isinstance(b,Iterable) >>> Trueisinstance(b,Iterator) >>> True#第二種:返回其他對象的迭代器class A(): def __init__(self): pass def __iter__(self): self.num = 0 return bclass B(A): def __next__(self): if self.num < 10: N = self.num self.num += 1 return N else: raise StopIteration #實例化兩個對象:a和b,當調用對象a的__iter__()方法時,返回對象b,B繼承于A類,所以b對象是一個迭代器。a = A()b = B()#調用a的__iter__()方法c = a.__iter__()from collections import Iterable,Iterator#由于對象a不具備__next__()方法,因此僅僅是一個可迭代對象isinstance(a,Iterable) >>> Trueisinstance(a,Iterator) >>> False#但是調用對象a的__iter()方法生成的c,同時具備__iter__()和__next__()方法,是一個迭代器。isinstance(c,Iterable) >>> Trueisinstance(c,Iterator) >>> True

上面兩種方式表示可以生成迭代器,但并不是使用這兩個函數就一定生成迭代器,這取決于運行這兩個函數返回的是什么

#iter()函數:其運行機制是尋找對象中的__iter__()方法,運行并返回結果,如果__iter__()方法返回的不是迭代器,則此方法會報錯;如果沒有此方法,則尋找__getitem__()方法。class A(): def __init__(self): pass def __iter__(self): return 1 #我們知道數字1不是迭代器,此函數返回的是一個非迭代器 a = A()b = iter(a)Traceback (most recent call last): File '<input>', line 10, in <module>TypeError: iter() returned non-iterator of type ’int’#直接調用__iter__()方法:如果想通過調用此方法生成迭代器,只能定義在此函數下返回一個迭代器;如果定義返回的不是迭代器,調用此方法是不會生成迭代器的。class A(): def __init__(self): pass def __iter__(self): return 1 a = A()#直接調用__iter__()方法b = a.__iter__()#我們可以看到返回的是1,而不是迭代器,只有當你定義返回迭代器時,調用此方法才會返回迭代器print(b) >>> 1判斷對象是否是可迭代對象:1.collections模塊的Iterable類型,使用isinstance()判斷(此方法不太準)

#我們定義一個類:具有__iter__()方法,但返回的不是迭代器class A(): def __init__(self): pass def __iter__(self): return 1 a = A()from collections import Iterable#我們使用isinstance()結合collections看一下:會發現此方法認為他是一個可迭代對象isinstance(a,Iterable) >>> True#我們使用for...in進行循環訪問,發現并不能for i in a: print(i) Traceback (most recent call last): File '<input>', line 1, in <module>TypeError: iter() returned non-iterator of type ’int’#接下來,我們再定義一個類:具有__iter__()方法和__next__()方法,但返回的不是迭代器class A(): def __init__(self): pass def __iter__(self): pass def __next__(self): passa = A()from collections import Iterator#我們使用isinstance()結合collections看一下:會發現此方法認為他是一個迭代器isinstance(a,Iterator) >>> True#我們使用for...in進行循環訪問,發現并不能for i in a: print(a) Traceback (most recent call last): File '<input>', line 1, in <module>TypeError: iter() returned non-iterator of type ’NoneType’2.使用iter()內置函數進行判斷:

class A(): def __init__(self): pass def __iter__(self): return 1 a = A()#使用iter()函數如果報錯,則不是可迭代對象,如果不報錯,則是可迭代對象b = iter(a)Traceback (most recent call last): File '<input>', line 1, in <module>TypeError: iter() returned non-iterator of type ’int’3.使用for…in方法進行遍歷,如果可以遍歷,即為可迭代對象

#for...in循環的實質是:先調用對象的__iter__()方法,返回一個迭代器,然后不斷的調用迭代器的__next__()方法。class A(): def __init__(self): pass def __iter__(self): self.num = 0 return self def __next__(self): if self.num < 10: N = self.num self.num += 1 return N else: raise StopIterationa = A()for i in a: print(i) >>> 0 1 2 3 4 5 6 7 8 9#等同于:先調用對象的__iter__()方法,返回一個迭代器,然后不斷的調用迭代器的__next__()方法,調用完返回StopIteration,結束迭代b = iter(a)while True: try: next(b) except: raise StopIteration0 1 2 3 4 5 6 7 8 9Traceback (most recent call last): File '<stdin>', line 3, in <module> File '<stdin>', line 13, in __next__StopIteration

經過上面三種判斷方法的分析,我們可以得出一些結論:1.collection模塊的Iterable,Iterator類型并不能準確的判斷對象是否是可迭代對象,或者是否是迭代器,它的判斷原理只是檢查對象內部是否定義了__iter__()和__next__()方法,而不注重這兩個函數所返回的內容。2.相比于collections模塊,iter()函數則與其不同,它更注重__iter__()函數返回的內容,如果返回的是迭代器,則iter()的參數即為可迭代對象,否則,使用iter()函數會報錯。此方法比較常用,也相對好用。3.for…in循環方法,也可以用來判斷對象是否是可迭代對象,此方法本質就是調用對象__iter__()和__next__()方法,他同樣注重函數的返回內容。

經過以上種種實例的分析,我們發現僅僅具有__iter__()和__next__方法并不能算真正意義上的可迭代對象或者迭代器,如果不注重方法返回的內容,實例化的對象卻不能進行迭代訪問,又怎么能稱為可迭代對象和迭代器呢?因此我們在這里對可迭代對象和迭代器進行重新定義

類型 定義 判斷方法 - 可迭代對象 內部定義了__iter__()方法且返回迭代器,可以返回自己也可以返回其他迭代器,如果返回自己,則自己還必須定義__next__()方法;也可以是定義__getitem__()方法的序列,整數參數可以從0進行索引,一般來說,標準的序列均定義了__iter__()方法,所以序列也是符合可迭代對象的要求的 可以使用iter()方法進行判斷,將對象作為參數輸入,如果不報錯則為可迭代對象;反之,則不是。除此之外,使用for循環進行遍歷,也可以識別;還有就是能夠看到對象的源碼,直接根據定義進行判斷 迭代器 內部定義了__iter__()方法,與可迭代對象不同的是,對象的__iter__()方法必須返回的是自己,同時自己定義了__next__()方法 如果是迭代器,是可以調用__next__()方法的,調用所有元素后,拋出StopIteration錯誤;判斷Iterator最好是能夠看到源碼,直接根據定義判斷。 generator ? 生成器:

生成器是一個用于創建迭代器的簡單而強大的工具。它們的寫法類似于標準的函數,但當它們要返回數據時會使用yield 語句。每次在生成器上調用next() 時,它會從上次離開的位置恢復執行(它會記住上次執行語句時的所有數據值)。

可以用生成器來完成的操作同樣可以用基于類的迭代器來完成。 但生成器的寫法更為緊湊,因為它會自動創建 iter() 和 next() 方法。

另一個關鍵特性在于局部變量和執行狀態會在每次調用之間自動保存。 這使得該函數相比使用 self.index 和 self.data 這種實例變量的方式更易編寫且更為清晰。

除了會自動創建方法和保存程序狀態,當生成器終結時,它們還會自動引發 StopIteration。 這些特性結合在一起,使得創建迭代器能與編寫常規函數一樣容易。

def A(): yield 1 yield 2 a = A()print(a)#可以看出a顯示的是一個生成器對象<generator object A at 0x7f4f94409eb8>#我們使用dir()函數看一下生成器的方法:dir(a)[’省略’, ’__iter__’, ’省略’, ’__next__’, ’send’, ’throw’,’省略’]#可以看到生成器里面自動完成了對__iter__()和__next__()方法的定義#我們調用對象的__iter__()方法print(iter(a)) >>> <generator object A at 0x7f4f94409eb8>print(a) >>> <generator object A at 0x7f4f94409eb8>#可以看到,調用__iter__()方法,返回的是對象自己#我們調用對象的__next__()方法next(a) >>> 1#可以看到,再次調用next()方法,是在上次的基礎上繼續運行的,返回的是2,而不是像普通函數一樣,從頭開始重新運行next(a) >>> 2next(a)Traceback (most recent call last): File '<stdin>', line 1, in <module>StopIteration#可以看到生成器a調用next()方法后生成下一個元素,同時當元素耗盡時,拋出StopIteration錯誤,這和迭代器完全相似#生成器完全符合迭代器的要求,所以生成器也屬于迭代器

除了定義一個yield函數外,還可以利用推導式生成一個生成器

#一般的推導式有列表推導式和字典推導式,與兩者不同,生成器的推導式是寫在小括號中的,而且只能是比較簡單的生成器,比較復雜的生成器一般是寫成yield函數的形式.a = (i for i in range(5))print(a)<generator object <genexpr> at 0x03CFDE28> 類型 定義 判斷方法 生成器 使用yield的函數,或者類似(i for i in range(5))這樣的推導式,自動實現__iter__()和__next__()方法 根據定義判斷

1.生成器是一種特殊的迭代器,其內部自動實現__iter__()和__next__()方法,可用for循環遍歷輸出;2.迭代器一定是可迭代對象,但可迭代對象不一定是迭代器。

迭代器存在的意義:

在說明迭代器之前,我們需要引入一個容器的概念。什么是容器?容器是眾多對象(在python中對象的抽象是類class)的集合,根據存儲方式不同,python可分為四種容器:

列表(list):對象以隊列方式進行存儲 元組(tuple):對象以隊列方式進行存儲,和列表一樣,只是存儲數據后,不可更改, 集合(set):對象以無序的方式進行存儲 字典(dict):對象以鍵值對映射的方式存儲數據

在編程中,最常見的操作就是從這些容器中拿出數據。而容器一般是不具備取出數據的功能的。我們平時取出數據的操作實際上是先經過__iter__()方法轉為迭代器,之后再通過__next__()方法拿取的(參考for循環,map(),filter())。可以說迭代器賦予了容器取出數據的能力,但迭代器每次調用__next__()方法只能取出一個數據,這種方法顯然是很笨拙的,于是引入for循環,每次循環自動調用__next__()方法,這使得訪問容器中的對象變得十分方便。

個人理解:迭代器的存在類似指針。

迭代器具有__iter__()方法就好比具備存放指針的資格,而__next__()方法,表示指針調度的規則。每次訪問容器中的元素,首先調用__iter__()方法在容器元素頭部放一個指針,此指針不指向任何元素,位于所有元素前面,為待操作狀態,隨時準備被調用。然后通過__next__()方法制定的規則來調度這個指針,使其指向不同的對象,指針所指之處便是所訪問對象。此指針默認有一些屬性:只能向前,不能回退,當沒有元素時,拋出StopIteration,過程結束。

python學習之可迭代對象、迭代器、生成器

使用迭代器一個明顯的優勢是:減少內存占用

不使用迭代器:如果我們想訪問一個容器中的所有元素,就需要將所有的元素都加載到內存中,然后一次性打印,對于少量元素來說,這無關緊要,但當數據量非常大時,這種做法將占用很大的內存,影響程序性能。使用迭代器:我們訪問一個容器中的所有元素,不會將所有元素都加載出來,而是一個一個的加載,然后打印,這樣會極大的減少內存的占用。

生成器存在的意義:

生成器的存在,給我更多的感受是:簡化迭代器的生成。我們只需使用yield關鍵字,將數據處理的邏輯寫出,對象內部將自動完成對__iter__()和__next__()方法的定義,使我們不用再耗費精力處理實例變量,以及自己定義__iter__()和__next__()方法。

特性:

1.生成器中的成員并不存在,使用一個成員立刻用yield生成一個成員(按需計算)2.生成器很節省內存,因為是立刻生成的,所以耗費CPU進行計算;

到此這篇關于python學習之可迭代對象、迭代器、生成器的文章就介紹到這了,更多相關python可迭代對象、迭代器、生成器內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Python 編程
相關文章:
主站蜘蛛池模板: 女神穿上情趣丝袜啪啪一整晚 | 欧美亚洲一区二区三区 | 男女又黄又刺激黄a大片桃色 | 婷婷在线网 | 婷婷射 | 在线视频欧美日韩 | 国产欧美日韩另类 | 亚洲三级国产 | 亚洲啪啪免费视频 | 爱爱视频免费 | 久久国产精品岛国搬运工 | 达达兔欧美午夜国产亚洲 | 日韩中字在线 | 欧美精品亚洲精品日韩 | 91视频观看免费 | 黄频大全 | 久久精品视频6 | 伊人久久大香线蕉精品哪里 | 免费不卡毛片 | 久久中文字幕久久久久91 | 一级一级特黄女人精品毛片视频 | 免费一级毛片正在播放 | 亚洲美女一区 | 亚洲无线一二三四区手机 | 国产一区在线看 | 91黄视频 | 国产成人久久精品一区二区三区 | 中文字幕一区在线观看视频 | 亚洲美女色在线欧洲美女 | 亚洲精品在线免费看 | 免费看日日麻批免费视频播放 | 亚洲精品国产第一区二区三区 | 欧美精品在线免费 | 国产高清免费在线观看 | 韩国xxxxxxxx69 | 国产精品久久久久一区二区三区 | 久久国产欧美另类久久久 | 成年免费大片黄在看 | 国产精品v欧美精品v日韩 | 美国一级大黄大色毛片 | 91久久九九精品国产综合 |