【Python之迭代器,產生器】

來源:互聯網
上載者:User

標籤:方便   rgs   狀態   調用   pen   過程   表達   類型   輸出   

一、可迭代對象和迭代器1.迭代的概念

上一次輸出的結果為下一次輸入的初始值,重複的過程稱為迭代,每次重複即一次迭代,並且每次迭代的結果是下一次迭代的初始值 

註:迴圈不是迭代

while True: #只滿足重複,因而不是迭代     print(‘====>‘)

 

2.可迭代的對象內建__iter__方法的,都是可迭代的對象。

list是可迭代對象,dict是可迭代對象,set也是可迭代對象。

[1,2].__iter__()‘hello‘.__iter__()(1,2).__iter__(){‘a‘:1,‘b‘:2}.__iter__(){1,2,3}.__iter__()

 

例如:

x = [1, 2, 3]y = iter(x)z = iter(x)print(next(y))print(next(y))print(next(z))print(type(x))print(type(y))

輸出

121<class ‘list‘><class ‘list_iterator‘>

  

 

如所示

這裡x是一個可迭代對象,yz是兩個獨立的迭代器,迭代器內部持有一個狀態,該狀態用於記錄當前迭代所在的位置,以方便下次迭代的時候擷取正確的元素。

迭代器有一種具體的迭代器類型,比如list_iteratorset_iterator。可迭代對象實現了__iter__方法,該方法返回一個迭代器對象。

 

3.迭代器
  • 1.為什麼要有迭代器?

對於沒有索引的資料類型,必須提供一種不依賴索引的迭代方式。

 

  • 2.迭代器定義:

迭代器:可迭代對象執行__iter__方法,得到的結果就是迭代器,迭代器對象有__next__方法

它是一個帶狀態的對象,他能在你調用next()方法的時候返回容器中的下一個值,任何實現了__iter____next__()方法的對象都是迭代器,__iter__返回迭代器自身,__next__返回容器中的下一個值,如果容器中沒有更多元素了,則拋出StopIteration異常

 

  • 3.迭代器的實現

例:

i=[1,2,3].__iter__()  print(i)    #迭代器print(i.__next__())print(i.__next__())print(i.__next__())#print(i.__next__()) #拋出異常:StopIteration

輸出

<list_iterator object at 0x1019c3eb8>123

每次調用next()方法的時候做兩件事: 

  1. 為下一次調用next()方法修改狀態
  2. 為當前這次調用產生返回結果

迭代器就像一個懶載入的工廠,等到有人需要的時候才給它產生值返回,沒調用的時候就處於休眠狀態等待下一次調用。

 

  • 4.如何判斷迭代器對象和可迭代對象
from collections import Iterable,Iterator‘abc‘.__iter__()().__iter__()[].__iter__(){‘a‘:1}.__iter__(){1,2}.__iter__()f=open(‘a.txt‘,‘w‘)f.__iter__()
#判斷是否為可迭代對象,以下都是print(isinstance(‘abc‘,Iterable))print(isinstance([],Iterable))print(isinstance((),Iterable))print(isinstance({‘a‘:1},Iterable))print(isinstance({1,2},Iterable))print(isinstance(f,Iterable))
#判斷是否為迭代器,只有檔案是print(isinstance(‘abc‘,Iterator))print(isinstance([],Iterator))print(isinstance((),Iterator))print(isinstance({‘a‘:1},Iterator))print(isinstance({1,2},Iterator))print(isinstance(f,Iterator))

輸出

TrueTrueTrueTrueTrueTrueFalseFalseFalseFalseFalseTrue

 

可迭代對象:只有__iter__方法,執行該方法得到的迭代器對象

迭代器:有__iter____next__()方法

註:對於迭代器對象來說,執行__iter__方法,得到的結果仍然是它本身

 

  • 5.迭代器的優點和缺點

優點:
1.提供了一種不依賴下標的迭代方式
2.就跌迭代器本身來說,更節省記憶體

缺點:
1. 無法擷取迭代器對象的長度
2. 不如序列類型取值靈活,是一次性的,只能往後取值,不能往前退

 

二、產生器1.定義

產生器(generator)是一個特殊的迭代器,它的實現更簡單優雅,yield是產生器實現__next__()方法的關鍵。它作為產生器執行的暫停復原點,可以對yield運算式進行賦值,也可以將yield運算式的值返回。

也就是說,yield是一個文法糖,內部實現支援了迭代器協議,同時yield內部是一個狀態機器,維護著掛起和繼續的狀態。

 

yield的功能:
1.相當於為函數封裝好__iter__和__next__
2.return只能返回一次值,函數就終止了,而yield能返回多次值,每次返回都會將函數暫停,下一次next會從上一次暫停位置繼續執行

例:

def counter(n):    print(‘start...‘)    i=0    while i < n:        yield i        i+=1    print(‘end...‘)g=counter(5)print(g)print(next(g))print(next(g))print(next(g))print(next(g))print(next(g))# print(next(g))   #會報錯

輸出

start...01234

 

 

2.產生器函數
  • 產生器函數:常規函數定義,但是,使用yield語句而不是return語句返回結果。yield語句一次返回一個結果,在每個結果中間,掛起函數的狀態,以便下次重它離開的地方繼續執行;

 

普通函數return返回

def lay_eggs(num):    egg_list=[]    for egg in range(num):        egg_list.append(‘蛋%s‘ %egg)    return egg_listyikuangdan=lay_eggs(10) #我們拿到的是蛋print(yikuangdan)

輸出

[‘蛋0‘, ‘蛋1‘, ‘蛋2‘, ‘蛋3‘, ‘蛋4‘, ‘蛋5‘, ‘蛋6‘, ‘蛋7‘, ‘蛋8‘, ‘蛋9‘]

 

迭代器函數

def lay_eggs(num):    for egg in range(num):        res=‘蛋%s‘ %egg        yield res       #產生器關鍵文法        print(‘下完一個蛋‘)laomuji=lay_eggs(10) #我們拿到的是一隻母雞print(laomuji)print(laomuji.__next__())       #迭代  蛋0print(laomuji.__next__())     #蛋1print(laomuji.__next__())       #蛋2egg_l=list(laomuji)print(egg_l)

輸出

蛋0下完一個蛋蛋1下完一個蛋蛋2下完一個蛋下完一個蛋下完一個蛋下完一個蛋下完一個蛋下完一個蛋下完一個蛋下完一個蛋[‘蛋3‘, ‘蛋4‘, ‘蛋5‘, ‘蛋6‘, ‘蛋7‘, ‘蛋8‘, ‘蛋9‘]

 

3.產生器運算式
  • 產生器運算式:類似於列表推導,但是,產生器返回按需產生結果的一個對象,而不是一次構建一個結果清單;
  • food=yield food_list

    #g.send(‘food1‘),先把food1傳給yield,由yield賦值給food,然後返回給food_list,然後再往下執行,直到再次碰到yield,然後把yield後的傳回值返回給food_list

注意:開始產生器不能send非空值

def eater(name):        #協程函數    print(‘%s ready to eat‘ %name)    food_list=[]    while True:        food=yield food_list           #裝飾器運算式        food_list.append(food)        print(‘%s start to eat %s‘ %(name,food))g=eater(‘hexin‘)print(g)        #產生器

print(g.send(‘food1‘)) #傳值

輸出

Traceback (most recent call last):<generator object eater at 0x1049030f8>    #產生器對象  File "/Users/hexin/PycharmProjects/py3/day5/2.py", line 71, in <module>    print(g.send(‘food1‘))TypeError: can‘t send non-None value to a just-started generator    #開始產生器不能send非空值

 

  • 初始化後
def eater(name):        #協程函數    print(‘%s ready to eat‘ %name)    food_list=[]    while True:        food=yield food_list           #裝飾器運算式        food_list.append(food)        print(‘%s start to eat %s‘ %(name,food))g=eater(‘hexin‘)print(g)        #產生器next(g) #等同於 g.send(None),初始化print(g.send(‘food1‘))

輸出

<generator object eater at 0x107cde258>hexin ready to eathexin start to eat food1[‘food1‘]

 

  • 為了防止忘記初始化,可利用裝飾器進行初始化,如下
def deco(func):     #初始化函數    def wrapper(*args,**kwargs):        res=func(*args,**kwargs)        next(res)          #等同於 g.send(None),初始化        return res    return wrapper@deco       #用初始化函數裝飾器,調用初始化函數def eater(name):        #協程函數    print(‘%s ready to eat‘ %name)    food_list=[]    while True:        food=yield food_list           #裝飾器運算式        food_list.append(food)        print(‘%s start to eat %s‘ %(name,food))g=eater(‘hexin‘)# print(g)        #產生器# next(g) #等同於 g.send(None),初始化print(g.send(‘food1‘))print(g.send(‘food2‘))print(g.send(‘food3‘))

輸出

hexin ready to eathexin start to eat food1[‘food1‘]hexin start to eat food2[‘food1‘, ‘food2‘]hexin start to eat food3[‘food1‘, ‘food2‘, ‘food3‘]

 

 

【Python之迭代器,產生器】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.