主頁(yè) > 知識(shí)庫(kù) > python學(xué)習(xí)之可迭代對(duì)象、迭代器、生成器

python學(xué)習(xí)之可迭代對(duì)象、迭代器、生成器

熱門(mén)標(biāo)簽:電話(huà)外呼系統(tǒng)招商代理 佛山通用400電話(huà)申請(qǐng) 電話(huà)機(jī)器人貸款詐騙 廣東旅游地圖標(biāo)注 蘇州人工外呼系統(tǒng)軟件 京華圖書(shū)館地圖標(biāo)注 淮安呼叫中心外呼系統(tǒng)如何 看懂地圖標(biāo)注方法 打印谷歌地圖標(biāo)注

Iterable – 可迭代對(duì)象

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

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

判斷對(duì)象是否為可迭代對(duì)象:可以使用isinstance與collections模塊的Iterable類(lèi)型

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

通過(guò)上面我們得到可迭代對(duì)象有:字符串,元組,列表,字典,集合
我們可以使用內(nèi)置的dir()函數(shù)對(duì)python數(shù)據(jù)類(lèi)型進(jìn)行操作,會(huì)發(fā)現(xiàn)可迭代對(duì)象(str,tuple,list,dict,set)均實(shí)現(xiàn)了__iter__方法,而不是可迭代對(duì)象的int類(lèi)型則沒(méi)有__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__方法決定對(duì)象是否是可迭代對(duì)象呢?我們可以驗(yàn)證一下:

#自定義兩個(gè)類(lèi):A類(lèi)和B類(lèi),其中B類(lèi)實(shí)現(xiàn)__iter__方法,A類(lèi)則沒(méi)有
from collections import Iterable
class A():
... def __init__(self):
... pass
... 
class B():
 def __init__(self):
 pass
 def __iter__(self):
 return self
#生成兩個(gè)實(shí)例化對(duì)象:a和b 
a = A()
b = B()
#可以看到實(shí)現(xiàn)__iter__方法的b對(duì)象是可迭代對(duì)象,而a對(duì)象不是
isinstance(a,Iterable) >>> False
isinstance(b,Iterable) >>> True

特殊情況:實(shí)現(xiàn)了__getitem__方法的序列也是可迭代對(duì)象

sequence – 序列
一種 iterable,它支持通過(guò)__getitem__() 特殊方法來(lái)使用整數(shù)索引進(jìn)行高效的元素訪(fǎng)問(wèn),并定義了一個(gè)返回序列長(zhǎng)度的__len__() 方法。內(nèi)置的序列類(lèi)型有l(wèi)ist、str、tuple 和 bytes。注意雖然 dict 也支持__getitem__() 和__len__(),但它被認(rèn)為屬于映射而非序列,因?yàn)樗檎視r(shí)使用任意的 immutable 鍵而非整數(shù)。

#自定義一個(gè)實(shí)現(xiàn)__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')
#可以看到實(shí)例化后的對(duì)象是可以通過(guò)for...in進(jìn)行循環(huán)訪(fǎng)問(wèn)的,表示其是可迭代對(duì)象。
for i in range(len(a)):
 print(a[i]) >>> 1 2 3 ss dd 
#我們使用collections模塊的Iterable進(jìn)行判斷:
from collections import Iterable,Iterator
isinstance(a,Iterable) >>> False
#結(jié)果出乎意料,判定對(duì)象a不是可迭代對(duì)象,為什么呢?
#因?yàn)閏ollections模塊的Iterable自動(dòng)忽略了對(duì)象的__getitem__方法,只根據(jù)對(duì)象是否有__iter__方法進(jìn)行判斷。一般來(lái)說(shuō),標(biāo)準(zhǔn)的序列均實(shí)現(xiàn)了__iter__方法。
#既然上面方法無(wú)法判斷具有__getitem__方法的序列是否是可迭代對(duì)象,那又該如何判斷呢?
#可以使用iter()函數(shù),如果不報(bào)錯(cuò),說(shuō)明是可迭代對(duì)象,報(bào)錯(cuò)就不是
b = iter(a)
isinstance(b,Iterable) >>> True
isinstance(b,Iterator) >>> True

Iterator – 迭代器:內(nèi)部實(shí)現(xiàn)__iter__和__next__方法的對(duì)象

用來(lái)表示一連串?dāng)?shù)據(jù)流的對(duì)象。重復(fù)調(diào)用迭代器的 next() 方法(或?qū)⑵鋫鹘o內(nèi)置函數(shù) next())將逐個(gè)返回流中的項(xiàng)。當(dāng)沒(méi)有數(shù)據(jù)可用時(shí)則將引發(fā) StopIteration 異常。到這時(shí)迭代器對(duì)象中的數(shù)據(jù)項(xiàng)已耗盡,繼續(xù)調(diào)用其 next() 方法只會(huì)再次引發(fā) StopIteration 異常。迭代器必須具有 iter() 方法用來(lái)返回該迭代器對(duì)象自身,因此迭代器必定也是可迭代對(duì)象,可被用于其他可迭代對(duì)象適用的大部分場(chǎng)合。一個(gè)顯著的例外是那些會(huì)多次重復(fù)訪(fǎng)問(wèn)迭代項(xiàng)的代碼。容器對(duì)象(例如 list)在你每次向其傳入 iter() 函數(shù)或是在 for 循環(huán)中使用它時(shí)都會(huì)產(chǎn)生一個(gè)新的迭代器。如果在此情況下你嘗試用迭代器則會(huì)返回在之前迭代過(guò)程中被耗盡的同一迭代器對(duì)象,使其看起來(lái)就像是一個(gè)空容器。

判斷對(duì)象是否為迭代器:使用isinstance與collections模塊的Iterator類(lèi)型

from collections import Iterable,Iterator
#創(chuàng)建兩個(gè)類(lèi):B類(lèi)和C類(lèi),B類(lèi)實(shí)現(xiàn)了__iter__方法,C類(lèi)實(shí)現(xiàn)了__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
#實(shí)例化兩個(gè)對(duì)象 
b = B()
c = C()
#可以看到b對(duì)象是可迭代對(duì)象,卻不是迭代器;c對(duì)象既是可迭代對(duì)象,又是迭代器.
isinstance(b,Iterable) >>> True
isinstance(b,Iterator) >>> False
isinstance(c,Iterator) >>> True
isinstance(c,Iterable) >>> True

生成迭代器有兩種方法:

1.使用內(nèi)置的iter(object[, sentinel])函數(shù);

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

iter()的第一種形式:不帶第二個(gè)參數(shù),第一個(gè)參數(shù)表示可迭代對(duì)象(具有__iter__()方法或者_(dá)_getitem__()方法)

#自定義兩個(gè)類(lèi),一個(gè)支持__iter__()方法,一個(gè)支持__getitem__()方法
#1.定義一個(gè)支持迭代協(xié)議的集合對(duì)象:
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類(lèi)中我們定義的__iter__()函數(shù)是返回自己,同時(shí)定義了自身的__next__()方法,所以對(duì)象a既是可迭代對(duì)象,又是迭代器。
isinstance(a,Iterable) >>> True
isinstance(a,Iterator) >>> True
#同時(shí)我們可以看到對(duì)象a經(jīng)過(guò)iter()方法后生成的b對(duì)象是迭代器。
isinstance(b,Iterator) >>> True
isinstance(b,Iterable) >>> True

#定義一個(gè)支持序列協(xié)議的對(duì)象
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 num

b = B()
c = iter(b)

#由于b對(duì)象定義的是__getitem__()方法,所以無(wú)法使用collections模塊對(duì)b對(duì)象進(jìn)行判斷。
#這里我們只對(duì)使用了iter()方法后生成的c對(duì)象進(jìn)行判斷
isinstance(c,Iterable) >>> True
isinstance(c,Iterator) >>> True
#可以看到使用了iter()方法后生成的對(duì)象c是迭代器

iter()的第二種形式:帶第二個(gè)參數(shù),第一個(gè)參數(shù)表示可調(diào)用對(duì)象,當(dāng)返回值為第二個(gè)參數(shù)時(shí),觸發(fā)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對(duì)象既不是可迭代對(duì)象也不是迭代器,但通過(guò)iter()方法返回的對(duì)象b確實(shí)迭代器
isinstance(a,Iterable) >>> False
isinstance(a,Iterator) >>> False
isinstance(b,Iterator) >>> True
isinstance(b,Iterable) >>> True
#通過(guò)for...in循環(huán)遍歷打?。看窝h(huán)都調(diào)用__call__()方法,直至返回值等于5,觸發(fā)StopIteration停止迭代)
for i in b:
 print(i) >>> 1 2 3 4
 
#iter()的第二種形式的一個(gè)有用的應(yīng)用是構(gòu)建塊讀取器。例如,從二進(jìn)制數(shù)據(jù)庫(kù)文件中讀取固定寬度的塊,直到到達(dá)文件結(jié)尾:
from functools import partial
with open('mydata.db', 'rb') as f:
 for block in iter(partial(f.read, 64), b''):
 process_block(block)

2.直接調(diào)用可迭代對(duì)象的__iter__方法;

#定義__iter__()方法,可以返回自己,但自己要定義__next__()方法;也可以返回其他對(duì)象的迭代器
#第一種:返回自身,同時(shí)定義自身的__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 StopIteration
a = A()
b = a.__iter__()
from collections import Iterable,Iterator
#由于A類(lèi)中我們定義的__iter__()函數(shù)是返回自己,同時(shí)定義了自身的__next__()方法,所以對(duì)象a既是可迭代對(duì)象,又是迭代器。
isinstance(a,Iterable) >>> True
isinstance(a,Iterator) >>> True
#同時(shí)我們可以看到對(duì)象a經(jīng)過(guò)iter()方法后生成的b對(duì)象是迭代器。
isinstance(b,Iterable) >>> True
isinstance(b,Iterator) >>> True

#第二種:返回其他對(duì)象的迭代器
class A():
 def __init__(self):
 pass
 def __iter__(self):
 self.num = 0
 return b

class B(A):
 def __next__(self):
 if self.num  10:
 N = self.num
 self.num += 1
 return N
 else:
 raise StopIteration
 
#實(shí)例化兩個(gè)對(duì)象:a和b,當(dāng)調(diào)用對(duì)象a的__iter__()方法時(shí),返回對(duì)象b,B繼承于A類(lèi),所以b對(duì)象是一個(gè)迭代器。
a = A()
b = B()
#調(diào)用a的__iter__()方法
c = a.__iter__()
from collections import Iterable,Iterator
#由于對(duì)象a不具備__next__()方法,因此僅僅是一個(gè)可迭代對(duì)象
isinstance(a,Iterable) >>> True
isinstance(a,Iterator) >>> False
#但是調(diào)用對(duì)象a的__iter()方法生成的c,同時(shí)具備__iter__()和__next__()方法,是一個(gè)迭代器。
isinstance(c,Iterable) >>> True
isinstance(c,Iterator) >>> True

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

#iter()函數(shù):其運(yùn)行機(jī)制是尋找對(duì)象中的__iter__()方法,運(yùn)行并返回結(jié)果,如果__iter__()方法返回的不是迭代器,則此方法會(huì)報(bào)錯(cuò);如果沒(méi)有此方法,則尋找__getitem__()方法。
class A():
 def __init__(self):
 pass
 def __iter__(self):
 return 1 #我們知道數(shù)字1不是迭代器,此函數(shù)返回的是一個(gè)非迭代器 
a = A()
b = iter(a)
Traceback (most recent call last):
 File "input>", line 10, in module>
TypeError: iter() returned non-iterator of type 'int'

#直接調(diào)用__iter__()方法:如果想通過(guò)調(diào)用此方法生成迭代器,只能定義在此函數(shù)下返回一個(gè)迭代器;如果定義返回的不是迭代器,調(diào)用此方法是不會(huì)生成迭代器的。
class A():
 def __init__(self):
 pass
 def __iter__(self):
 return 1 
a = A()
#直接調(diào)用__iter__()方法
b = a.__iter__()
#我們可以看到返回的是1,而不是迭代器,只有當(dāng)你定義返回迭代器時(shí),調(diào)用此方法才會(huì)返回迭代器
print(b) >>> 1

判斷對(duì)象是否是可迭代對(duì)象:

1.collections模塊的Iterable類(lèi)型,使用isinstance()判斷(此方法不太準(zhǔn))

#我們定義一個(gè)類(lèi):具有__iter__()方法,但返回的不是迭代器
class A():
 def __init__(self):
 pass
 def __iter__(self):
 return 1 
a = A()
from collections import Iterable
#我們使用isinstance()結(jié)合collections看一下:會(huì)發(fā)現(xiàn)此方法認(rèn)為他是一個(gè)可迭代對(duì)象
isinstance(a,Iterable) >>> True
#我們使用for...in進(jìn)行循環(huán)訪(fǎng)問(wèn),發(fā)現(xiàn)并不能
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'
#接下來(lái),我們?cè)俣x一個(gè)類(lèi):具有__iter__()方法和__next__()方法,但返回的不是迭代器
class A():
 def __init__(self):
 pass
 def __iter__(self):
 pass
 def __next__(self):
 pass

a = A()
from collections import Iterator
#我們使用isinstance()結(jié)合collections看一下:會(huì)發(fā)現(xiàn)此方法認(rèn)為他是一個(gè)迭代器
isinstance(a,Iterator) >>> True
#我們使用for...in進(jìn)行循環(huán)訪(fǎng)問(wèn),發(fā)現(xiàn)并不能
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()內(nèi)置函數(shù)進(jìn)行判斷:

class A():
 def __init__(self):
 pass
 def __iter__(self):
 return 1 
a = A()
#使用iter()函數(shù)如果報(bào)錯(cuò),則不是可迭代對(duì)象,如果不報(bào)錯(cuò),則是可迭代對(duì)象
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方法進(jìn)行遍歷,如果可以遍歷,即為可迭代對(duì)象

#for...in循環(huán)的實(shí)質(zhì)是:先調(diào)用對(duì)象的__iter__()方法,返回一個(gè)迭代器,然后不斷的調(diào)用迭代器的__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 StopIteration
a = A()
for i in a:
 print(i) >>> 0 1 2 3 4 5 6 7 8 9

#等同于:先調(diào)用對(duì)象的__iter__()方法,返回一個(gè)迭代器,然后不斷的調(diào)用迭代器的__next__()方法,調(diào)用完返回StopIteration,結(jié)束迭代
b = iter(a)
while True:
 try:
 next(b)
 except:
 raise StopIteration

0 1 2 3 4 5 6 7 8 9
Traceback (most recent call last):
 File "stdin>", line 3, in module>
 File "stdin>", line 13, in __next__
StopIteration

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

經(jīng)過(guò)以上種種實(shí)例的分析,我們發(fā)現(xiàn)僅僅具有__iter__()和__next__方法并不能算真正意義上的可迭代對(duì)象或者迭代器,如果不注重方法返回的內(nèi)容,實(shí)例化的對(duì)象卻不能進(jìn)行迭代訪(fǎng)問(wèn),又怎么能稱(chēng)為可迭代對(duì)象和迭代器呢?因此我們?cè)谶@里對(duì)可迭代對(duì)象和迭代器進(jìn)行重新定義

類(lèi)型 定義 判斷方法
-     可迭代對(duì)象 內(nèi)部定義了__iter__()方法且返回迭代器,可以返回自己也可以返回其他迭代器,如果返回自己,則自己還必須定義__next__()方法;也可以是定義__getitem__()方法的序列,整數(shù)參數(shù)可以從0進(jìn)行索引,一般來(lái)說(shuō),標(biāo)準(zhǔn)的序列均定義了__iter__()方法,所以序列也是符合可迭代對(duì)象的要求的 可以使用iter()方法進(jìn)行判斷,將對(duì)象作為參數(shù)輸入,如果不報(bào)錯(cuò)則為可迭代對(duì)象;反之,則不是。除此之外,使用for循環(huán)進(jìn)行遍歷,也可以識(shí)別;還有就是能夠看到對(duì)象的源碼,直接根據(jù)定義進(jìn)行判斷
迭代器 內(nèi)部定義了__iter__()方法,與可迭代對(duì)象不同的是,對(duì)象的__iter__()方法必須返回的是自己,同時(shí)自己定義了__next__()方法 如果是迭代器,是可以調(diào)用__next__()方法的,調(diào)用所有元素后,拋出StopIteration錯(cuò)誤;判斷Iterator最好是能夠看到源碼,直接根據(jù)定義判斷。

generator – 生成器:

生成器是一個(gè)用于創(chuàng)建迭代器的簡(jiǎn)單而強(qiáng)大的工具。它們的寫(xiě)法類(lèi)似于標(biāo)準(zhǔn)的函數(shù),但當(dāng)它們要返回?cái)?shù)據(jù)時(shí)會(huì)使用yield 語(yǔ)句。每次在生成器上調(diào)用next() 時(shí),它會(huì)從上次離開(kāi)的位置恢復(fù)執(zhí)行(它會(huì)記住上次執(zhí)行語(yǔ)句時(shí)的所有數(shù)據(jù)值)。

可以用生成器來(lái)完成的操作同樣可以用基于類(lèi)的迭代器來(lái)完成。 但生成器的寫(xiě)法更為緊湊,因?yàn)樗鼤?huì)自動(dòng)創(chuàng)建 iter() 和 next() 方法。

另一個(gè)關(guān)鍵特性在于局部變量和執(zhí)行狀態(tài)會(huì)在每次調(diào)用之間自動(dòng)保存。 這使得該函數(shù)相比使用 self.index 和 self.data 這種實(shí)例變量的方式更易編寫(xiě)且更為清晰。

除了會(huì)自動(dòng)創(chuàng)建方法和保存程序狀態(tài),當(dāng)生成器終結(jié)時(shí),它們還會(huì)自動(dòng)引發(fā) StopIteration。 這些特性結(jié)合在一起,使得創(chuàng)建迭代器能與編寫(xiě)常規(guī)函數(shù)一樣容易。

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

除了定義一個(gè)yield函數(shù)外,還可以利用推導(dǎo)式生成一個(gè)生成器

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

1.生成器是一種特殊的迭代器,其內(nèi)部自動(dòng)實(shí)現(xiàn)__iter__()和__next__()方法,可用for循環(huán)遍歷輸出;
2.迭代器一定是可迭代對(duì)象,但可迭代對(duì)象不一定是迭代器。

迭代器存在的意義:

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

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

在編程中,最常見(jiàn)的操作就是從這些容器中拿出數(shù)據(jù)。而容器一般是不具備取出數(shù)據(jù)的功能的。我們平時(shí)取出數(shù)據(jù)的操作實(shí)際上是先經(jīng)過(guò)__iter__()方法轉(zhuǎn)為迭代器,之后再通過(guò)__next__()方法拿取的(參考for循環(huán),map(),filter())??梢哉f(shuō)迭代器賦予了容器取出數(shù)據(jù)的能力,但迭代器每次調(diào)用__next__()方法只能取出一個(gè)數(shù)據(jù),這種方法顯然是很笨拙的,于是引入for循環(huán),每次循環(huán)自動(dòng)調(diào)用__next__()方法,這使得訪(fǎng)問(wèn)容器中的對(duì)象變得十分方便。

個(gè)人理解:迭代器的存在類(lèi)似指針。

迭代器具有__iter__()方法就好比具備存放指針的資格,而__next__()方法,表示指針調(diào)度的規(guī)則。每次訪(fǎng)問(wèn)容器中的元素,首先調(diào)用__iter__()方法在容器元素頭部放一個(gè)指針,此指針不指向任何元素,位于所有元素前面,為待操作狀態(tài),隨時(shí)準(zhǔn)備被調(diào)用。然后通過(guò)__next__()方法制定的規(guī)則來(lái)調(diào)度這個(gè)指針,使其指向不同的對(duì)象,指針?biāo)钢幈闶撬L(fǎng)問(wèn)對(duì)象。此指針默認(rèn)有一些屬性:只能向前,不能回退,當(dāng)沒(méi)有元素時(shí),拋出StopIteration,過(guò)程結(jié)束。

使用迭代器一個(gè)明顯的優(yōu)勢(shì)是:減少內(nèi)存占用

不使用迭代器:如果我們想訪(fǎng)問(wèn)一個(gè)容器中的所有元素,就需要將所有的元素都加載到內(nèi)存中,然后一次性打印,對(duì)于少量元素來(lái)說(shuō),這無(wú)關(guān)緊要,但當(dāng)數(shù)據(jù)量非常大時(shí),這種做法將占用很大的內(nèi)存,影響程序性能。
使用迭代器:我們?cè)L問(wèn)一個(gè)容器中的所有元素,不會(huì)將所有元素都加載出來(lái),而是一個(gè)一個(gè)的加載,然后打印,這樣會(huì)極大的減少內(nèi)存的占用。

生成器存在的意義:

生成器的存在,給我更多的感受是:簡(jiǎn)化迭代器的生成。我們只需使用yield關(guān)鍵字,將數(shù)據(jù)處理的邏輯寫(xiě)出,對(duì)象內(nèi)部將自動(dòng)完成對(duì)__iter__()和__next__()方法的定義,使我們不用再耗費(fèi)精力處理實(shí)例變量,以及自己定義__iter__()和__next__()方法。

特性:

1.生成器中的成員并不存在,使用一個(gè)成員立刻用yield生成一個(gè)成員(按需計(jì)算)
2.生成器很節(jié)省內(nèi)存,因?yàn)槭橇⒖躺傻模院馁M(fèi)CPU進(jìn)行計(jì)算;

到此這篇關(guān)于python學(xué)習(xí)之可迭代對(duì)象、迭代器、生成器的文章就介紹到這了,更多相關(guān)python可迭代對(duì)象、迭代器、生成器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Python基礎(chǔ)語(yǔ)法之容器詳解
  • python可迭代對(duì)象去重實(shí)例
  • Python編程如何在遞歸函數(shù)中使用迭代器
  • 一篇文章帶你了解python迭代器和生成器
  • 穩(wěn)扎穩(wěn)打?qū)WPython之容器 可迭代對(duì)象 迭代器 生成器專(zhuān)題講解

標(biāo)簽:畢節(jié) 江蘇 駐馬店 衡水 湖州 呼和浩特 股票 中山

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《python學(xué)習(xí)之可迭代對(duì)象、迭代器、生成器》,本文關(guān)鍵詞  python,學(xué),習(xí)之,可,迭代,對(duì)象,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《python學(xué)習(xí)之可迭代對(duì)象、迭代器、生成器》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于python學(xué)習(xí)之可迭代對(duì)象、迭代器、生成器的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章