日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
講解一下Python迭代器

迭代器指的是迭代取值的工具,迭代是指一個(gè)重復(fù)的過(guò)程,每一次重復(fù)都是基于上一次結(jié)果而來(lái)迭代提供了一種通用的不依賴索引的迭代取值方式,下面為大家詳細(xì)講解一下Python迭代器。

為涪城等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及涪城網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)、涪城網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

從for循環(huán)說(shuō)起

我們都知道,在Python中,我們可以for循環(huán)去遍歷一個(gè)列表,元組或者range對(duì)象。

for i in [1,2,3]:
   print(i)
for i in range(0,10):
   print(i)

那底層的原理是什么樣的呢?這其中涉及到了幾個(gè)概念,“可迭代”,“迭代器”,“生成器”等,大部分人可能聽(tīng)過(guò)這些名詞,但是他們具體的含義以及之間的關(guān)系可能沒(méi)搞清楚,以下就是它們之間的關(guān)系圖,接下來(lái)我們就來(lái)分析這個(gè)關(guān)系圖。

可迭代對(duì)象與迭代器(先不關(guān)心左邊的生成器)

如果一個(gè)對(duì)象是可迭代對(duì)象,那么我們就可以用for循環(huán)去遍歷它,比如列表、元組、字符串等都是可迭代對(duì)象。而我們用for循環(huán)去遍歷它的原理就是,先獲取了它的迭代器,然后使用迭代器的next方法去逐一遍歷。

a = [1,2,3]
# for相當(dāng)于下面的代碼
for i in a:
   print(i)
# for循環(huán)分解(實(shí)際是通過(guò)Python底層C語(yǔ)言實(shí)現(xiàn)的,此處只是演示)

## 第一步: 獲取迭代器
iterator_a = iter(a)
## 第二步: 通過(guò)next逐個(gè)遍歷
while True:
   try:
       print(next(iterator_a))
   except StopIteration:  ## 第三步:遇到StopIteration異常,停止
       break

注意可迭代對(duì)象與迭代器的區(qū)別,如果一個(gè)對(duì)象是可迭代對(duì)象,那么我們就肯定能調(diào)用iter()方法獲取它的迭代器,而如果一個(gè)對(duì)象是迭代器,我們就能用next()方法去拿下一個(gè)元素。 我們可以用isinstance判斷一個(gè)對(duì)象是不是可迭代對(duì)象,是不是迭代器。

>>> from collections.abc import Iterable
>>> from collections.abc import Iterator
>>> isinstance([1,2,3],Iterable)
True
>>> isinstance([1,2,3],Iterator)
False
>>> i = iter([1,2,3])
>>> isinstance(i, Iterable)
True
>>> isinstance(i, Iterator)
True
>>> type(i)

  
   'list_iterator'> 
  

列表本身不是迭代器,它是可迭代對(duì)象,所以你不能用next()操作列表

>>> a=[1,2]
>>> next(a)
Traceback (most recent call last):
 File "  " , line 1, in 
  
    TypeError: 
   'list' object is not an iterator >>> iter_a = iter(a) >>> next(iter_a) 1 >>> next(iter_a) 2 >>> next(iter_a)   
   # 當(dāng)沒(méi)有剩余元素時(shí),就拋出StopIteration異常 Traceback (most recent call last):  File 
   "  " , line 1, 
   in 
   
     StopIteration 
   
  

可迭代對(duì)象必須實(shí)現(xiàn)iter()函數(shù),返回迭代器,調(diào)用對(duì)象自身的iter()函數(shù)與將iter()作用于對(duì)象效果是一樣的,同理對(duì)next()和next()也一樣。

>>> a=[1,2,3]
>>> iter_a = a.__iter__()
>>> next(iter_a)
1
>>> iter_a.__next__()
2

有趣的是,迭代器也是一個(gè)可迭代的對(duì)象,所以它本身也需要實(shí)現(xiàn)iter()函數(shù),但是,一個(gè)迭代器的迭代器,是它本身,所以可能也有些多余了。

>>> a=[1,2,3]
>>> iter_a = iter(a)
>>> iter_b = iter(iter_a)
>>> iter_c = iter(iter_b)
>>> iter_a is iter_b
True
>>> iter_a == iter_c
True
>>> for x in iter_a:
...    print(x)
...
1
2
3

一些的迭代器類型

我們經(jīng)常會(huì)用到一些內(nèi)置的迭代器,例如filter和map,注意range是可迭代對(duì)象,但不是迭代器。

>>> from collections.abc import Iterator
>>> from collections.abc import Iterable
>>> a=range(10)
>>> isinstance(b, Iterable)
Traceback (most recent call last):
 File "  " , line 1, in 
  
    NameError: name 
   'b' is not defined >>> isinstance(a, Iterable) True >>> isinstance(a, Iterator) False >>> 
   type(a) 
   
    'range'> >>> 
    print(a) range(0, 10) 
   
  

filter

filter函數(shù)用于對(duì)一個(gè)列表進(jìn)行過(guò)濾,傳入一個(gè)函數(shù)和列表,這個(gè)函數(shù)返回值是True或者False,將列表的元素逐個(gè)傳入這個(gè)函數(shù),結(jié)果為True的保留,可以使用lambda函數(shù)。

注:在Python2.x中返回值為list,在Python3.x中返回迭代器

>>> from collections.abc import Iterator
>>> from collections.abc import Iterable
>>> a=filter(lambda x : x % 2 == 0, [1,2,3,4,5,6])
>>> isinstance(a, Iterable)
True
>>> isinstance(a, Iterator)
True
>>> type(a)

  
   'filter'> >>> 
   print(a) 
   
     >>> 
    for i 
    in a: ...  
    print(i) ... 2 4 6 
   
  

如果我們要想通過(guò)下表訪問(wèn),可以把它轉(zhuǎn)換成list

>>> a=filter(lambda x : x % 2 == 0, [1,2,3,4,5,6])
>>> a = list(a)
>>> a[0]
2

map

map函數(shù)接收一個(gè)函數(shù)與一個(gè)列表,將這個(gè)函數(shù)作用域列表的每個(gè)元素,生成一個(gè)新的序列,返回迭代器。

>>> from collections.abc import Iterator
>>> from collections.abc import Iterable
>>> a=map(lambda x : x * x, [1,2,3])
>>> isinstance(a, Iterable)
True
>>> isinstance(a, Iterator)
True
>>> type(a)

  
   'map'> >>>  
   print(i)  File 
   "  " , line 1    
   print(i)    ^ IndentationError: unexpected indent >>> 
   print(a) 
    >>> for i in a: ...   print(i) ... 1 4 9 
  

實(shí)現(xiàn)一個(gè)可迭代對(duì)象與它的迭代器

我們將list做一個(gè)簡(jiǎn)單的封裝,實(shí)現(xiàn)一個(gè)可迭代的mylist。

class mylist:
   def __init__(self, l):
       self.l = l

   def __iter__(self):
       return mylist_iterator(self.l)

class mylist_iterator:
   def __init__(self, l):
       self.l = l
       self.current = 0   # 記錄當(dāng)前迭代到哪個(gè)元素了        
   def __iter__(self): # 迭代器的迭代器返回自己即可
       return self  
   def __next__(self):
       if self.current return self.l[self.current-1]
       else:
           raise StopIteration

a = mylist([1,2])
for x in a:
   print(x)

i = iter(a)
print(next(i))
print(next(i))
print(next(i))

上述代碼并沒(méi)有實(shí)現(xiàn)迭代器帶來(lái)的好處,因?yàn)槲覀兪孪葌魅肓艘粋€(gè)列表進(jìn)去,假如這個(gè)列表很大,會(huì)占內(nèi)存。假如我們要實(shí)現(xiàn)一個(gè)類似range()功能,我們可以使用更有效的方法。

class myrange:
   def __init__(self, max_num):
       self.max_num = max_num

   def __iter__(self):
       return myrange_iterator(self.max_num)

class myrange_iterator:
   def __init__(self, max_num):
       self.max_num = max_num
       self.current = 0   # 記錄當(dāng)前迭代到哪個(gè)元素了        
   def __iter__(self): # 迭代器的迭代器返回自己即可
       return self  
   def __next__(self):
       if self.current return self.current-1
       else:
           raise StopIteration

a = myrange(2)
for x in a:
   print(x)

i = iter(a)
print(next(i))
print(next(i))
print(next(i))

需要注意的是,我們的myrange不能隨機(jī)訪問(wèn),只能一次性順序遍歷,只能前進(jìn),不能后退,實(shí)際Python的range()可以隨機(jī)訪問(wèn)。

for循環(huán)是否只能用于可迭代對(duì)象?

這個(gè)答案是No。for循環(huán)大部分情況都作用于可迭代對(duì)象,但是有一個(gè)例如,如果對(duì)象是可以通過(guò)下標(biāo)訪問(wèn)的,也能用于for循環(huán)。

一個(gè)對(duì)象如果不能用下標(biāo)訪問(wèn),那么就會(huì)報(bào)下面的錯(cuò)誤,實(shí)際上它對(duì)應(yīng)的是一個(gè)getitem()內(nèi)置方法。

>>> a={1,2,3}
>>> a[0]
Traceback (most recent call last):
 File "  " , line 1, in 
  
    TypeError: 
   'set' object is not subscriptable >>> a.__getitem__(1) Traceback (most recent call last):  File 
   "  " , line 1, 
   in 
   
     AttributeError: 
    'set' object has no attribute 
    '__getitem__' 
   
  

如果我們實(shí)現(xiàn)了getitem(),也能通過(guò)for循環(huán)遍歷。

from collections.abc import Iterator
from collections.abc import Iterable
class mylist1:
   def __init__(self, l):
       self.l = l

   def __getitem__(self, i):
       return self.l[i]

print(isinstance(a, Iterable))
print(isinstance(a, Iterator))

a = mylist1([1,2,3])
for x in a:
   print(x)

結(jié)果如下,可以看到a既不是可迭代對(duì)象,也不是迭代器。

False
False
1
2
3

for循環(huán)會(huì)先看對(duì)象是不是實(shí)現(xiàn)了iter(),如果是,就用迭代器的方式,如果沒(méi)有的話,就看有沒(méi)有getitem(),都沒(méi)有就報(bào)錯(cuò),報(bào)的錯(cuò)如下:

>>> for x in 5:
...   print(x)
...
Traceback (most recent call last):
 File "  " , line 1, in 
  
    TypeError: 
   'int' object is not iterable 
  

那我們?cè)趺粗浪热フ?strong>iter()呢?我們?cè)谇懊娴拇a里加上幾行,

from collections.abc import Iterator
from collections.abc import Iterable
class mylist1:
   def __init__(self, l):
       self.l = l

   def __getitem__(self, i):
       return self.l[i]
   def __iter__(self):
       return self
print(isinstance(a, Iterable))
print(isinstance(a, Iterator))
a = mylist1([1,2,3])
for x in a:
   print(x)

結(jié)果如下:

True
False
Traceback (most recent call last):

 File "  " , line 1, in 
  
       runfile(
   'C:/Users/xlniu/test123/test.py', wdir=
   'C:/Users/xlniu/test123')  File 
   "C:\Users\xlniu\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, 
   in runfile    execfile(filename, namespace)  File 
   "C:\Users\xlniu\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, 
   in execfile    
   exec(compile(f.read(), filename, 
   'exec'), namespace)  File 
   "C:/Users/xlniu/test123/test.py", line 49, 
   in 
   
        
    for x 
    in a: TypeError: iter() returned non-iterator of 
    type 
    'mylist1' 
   
  

特殊的迭代器-生成器(generator)

接下來(lái)我們看關(guān)系圖的左邊,生成器,生成器是迭代器,迭代器是可迭代對(duì)象,所以生成器肯定是可迭代對(duì)象了。哪些對(duì)象是生成器呢?

生成器的來(lái)源主要有兩個(gè),一個(gè)是生成器表達(dá)式,例如(i for i in ‘hello, world’), (i for i in range(0,10) if i % 2 == 0),另一個(gè)是生成器函數(shù),生成器函數(shù)不使用return返回?cái)?shù)據(jù),而使用yield。

我們來(lái)看一下前面說(shuō)的filter是不是生成器。

>>> from collections.abc import Iterator
>>> from collections.abc import Iterable
>>> from collections.abc import Generator
>>> a = [1,2,3,4,5,6]
>>> b = filter(lambda x : x % 2 == 0, a)
>>> print(isinstance(b, Generator))
False

它并不是一個(gè)生成器。

生成器表達(dá)式

生成器表達(dá)式與列表推斷是差不多的,但是它用”()”括起來(lái),而列表推斷用的中括號(hào),一般的語(yǔ)法就是:

expr(val) for val in xxx if yyy

例如

>>> from collections.abc import Generator
>>> a = (i for i in range(0, 10))
>>> next(a)
0
>>> next(a)
1
>>> print(isinstance(a, Generator))
True
>>> print(type(a))

  
   'generator'> >>> 
   print(a) 
   
     at 0x000001A61011B7C8>  
    #通過(guò)genexpr得到的生成器 >>> b = (i.upper() 
    for i 
    in 
    'hello, world') >>> c = (x 
    for x 
    in range(0,10) 
    if x % 5 == 0) >>> 
    for x 
    in b: ...  
    print(x) ... H E L L O , W O R L D >>> d = [i 
    for i 
    in range(0,10)] >>> 
    print(
    type(d)) >>> 
    type(d) 
    
     'list'> >>> 
     print(d) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    
   
  

如果我們把生成器表達(dá)式用在其他的對(duì)象上,例如set,list等,它們會(huì)自動(dòng)轉(zhuǎn)換成相應(yīng)類型。

>>> set(i for i in range(0,5))  # 相當(dāng)于set( (i for i in range(0,5)) )
{0, 1, 2, 3, 4}
>>> set( (i for i in range(0,5)) )
{0, 1, 2, 3, 4}
>>> tuple(i for i in range(0,5))
(0, 1, 2, 3, 4)
>>> list(i for i in range(0,5))
[0, 1, 2, 3, 4]

生成器函數(shù)

另外一種生成器通過(guò)生成器函數(shù)得到。

from collections.abc import Iterator
from collections.abc import Iterable
from collections.abc import Generator

def myrange(stop):
   i = 0
   while i #返回i,下次調(diào)用時(shí)會(huì)從這個(gè)地方繼續(xù)向下執(zhí)行
       i += 1

e = myrange(5)
print(isinstance(e, Iterable))
print(isinstance(e, Iterator))
print(isinstance(e, Generator))
print(type(e))
print(e)
print(next(e))
for x in e:
   print(x)

運(yùn)行結(jié)果如下:

True
True
True

  
   'generator'> 
   
     0 1 2 3 4 
   
  

在函數(shù)myrange中,有一個(gè)特殊的關(guān)鍵詞,yield。這個(gè)與return類似,但是return后,下次調(diào)用會(huì)從頭開(kāi)始,但是使用了yield,我們的函數(shù)就會(huì)返回一個(gè)生成器,相當(dāng)于每次執(zhí)行,都記住了上次的位置,從上次的位置繼續(xù)執(zhí)行。生成器表達(dá)式可以認(rèn)為是一種特殊的生成器函數(shù),類似于lambda表達(dá)式和普通函數(shù)。但是和生成器一樣,生成器表達(dá)式也是返回生成器generator對(duì)象,一次只返回一個(gè)值。


本文題目:講解一下Python迭代器
分享網(wǎng)址:http://www.dlmjj.cn/article/dhhdhcp.html