迭代器和生成器的用法

2022-08-20 21:42:17 字數 3773 閱讀 1552

首先在了解解析式之前,我們先來看乙個列子:乙個列表,元素是0-9,列表中的每個值自增1,該如何實現:

方法一:遍歷列表,對其元素進行加1操作後放到乙個新的列表中

1 lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]23

for index, i in

enumerate(lst):

4 lst[index] += 1

5print(lst)

方法二:通過map函式來實現

a = map(lambda x:x+1, lst)

print

(a)for x in

a:

print(x)

方法三:通過列表解析式,一行搞定

1 lst2 = [x+1 for x in

lst]

2print(lst2)

方法三就是列表解析式的寫法,返回乙個新的列表。

那麼什麼是生成器呢?通過列表解析式我們可以發現,它會直接建立乙個新的列表,這樣不好的地方就是占用記憶體,我們知道記憶體是有限的,如果列表中的元素有幾百萬,而有時候就僅僅需要個別的資料,那麼就會大大浪費記憶體的空間。

所以,我們是否可以想一種辦法來解決這個問題呢?在python中,生成器就很好的解決了這個問題。我們可以假設列表中的元素能否通過某種演算法來推算出來呢?在需要某個資料的時候通過計算來得到這個資料,這樣就不會直接生成乙個列表來儲存許多無用的資料了。在python中,這種一邊迴圈一邊計算的機制,就是生成器。

生成器是迭代器的一種,使用yield返回值函式,每次呼叫yield會暫停,使用next()函式和send()函式可以恢復生成器繼續下次計算。生成器不同於一般的函式會一次性返回所有資料,生成器一次只能產生乙個資料,這樣就不會占用大量的記憶體空間。

那麼如何去建立乙個生成器,這種方式比較簡單,就是將列表解析式的換成(),就可以建立乙個生成器(generator):

1 generator_demo = (x for x in range(6))

2print

(generator_demo)34

執行結果:

5at 0x0000000000c3e360>

從結果可以看出,生成器返回的是乙個generator物件。而列表解析式返回乙個列表。那麼如何去將生成器中的元素乙個乙個列印出來呢?這就需要next()函式來進行操作:

1 generator_demo = (x for x in range(3))23

print

(next(generator_demo))

4print

(next(generator_demo))

5print

(next(generator_demo))

6print

(next(generator_demo))78

執行結果:90

10 1

11 2

12traceback (most recent call last):

13 file "

c:/users/wj/pycharmprojects/mxonline/test.py

", line 10, in

14print

(next(generator_demo))

15 stopiteration

可以看出,生成器儲存的是演算法,通過next可以一次一次計算它的元素,直到最後乙個元素的時候繼續next會丟擲stopiteration的錯誤。在生產環境中,是基本不會用next這個方法的。因為生成器也是可迭代物件,可以通過for迴圈去迭代它的值:

1 generator_demo = (x for x in range(3))23

for x in

generator_demo:

4print(x)

通過這種方法來迭代它的值就不會丟擲stopiteration的錯誤了。

這種建立生成器的寫法固然簡單,但是如果是乙個演算法邏輯比較複雜的時候,就不適合通過這種簡單的寫法來建立生成器了,我們可以通過函式的形式來建立生成器,例如著名的斐波那契數列:

1

deffib(max):

2 n, a, b = 0, 0, 1

3while n 4 a, b = b, a+b

5print

(a)6 n += 178

return

'done

'

可以看出,fib函式實際上就是定義了斐波那契數列的運算規則,從第乙個元素開始,去推算出後面的元素,這種邏輯就非常想生成器。那麼我們就可以將這個函式去定義成乙個生成器函式,通過yield關鍵字來定義:

1

deffib(max):

2 n, a, b = 0, 0, 1

3while n 4yield

b5 a, b = b, a+b

6 n += 178

print(fib(10))910

執行結果:

11

從執行結果可以看出,返回了乙個generator物件,這就說明將這個函式定義成了乙個生成器函式。這裡說一下普通函式和生成器函式的執行流程,普通函式是順序執行的,遇到return關鍵字就返回函式的值退出函式。而生成器函式是每次呼叫next的時候執行,遇到yield關鍵字返回第乙個元素,然後將函式掛起,等待下一次喚醒繼續計算後面的值,也就是取多少用多少,不會去占用記憶體空間。

這個生成器函式也是可迭代物件,所以可以通過for迴圈去迭代他的值,而不用去通過next去取值。

我們還可以通過yield來實現在單執行緒模式下實現併發運算的效果:

1

import

time23

defconsumer(name):

4print('

{}老師說:準備上課了

'.format(name))

5while

true:

6 lesson = yield

7print('

開始{}了,{}老手來講課了!

'.format(lesson, name))89

10def

producer():

11 name1 = consumer('

張老手'

)12 name2 = consumer('

王老手'

)13 name1.__next__

()14 name2.__next__

()15

16for x in range(4):

17 time.sleep(1)

18print('

到了兩名同學')

19name1.send(x)

20 name2.send(x)

從這個例子的執行結果可以看出,next和send的區別,next是喚醒函式,返回一次值,send是喚醒函式,並向生成器內部yield傳遞乙個值,並改變yield的返回值。

那麼什麼是迭代器呢?迭代就是迴圈,是指在正確的範圍內返回期待的資料以及在超出範圍以後丟擲stopiteration的錯誤停止迭代。

可以直接作用於for迴圈的資料型別有,字串、列表、元組、字典、集合等,還有生成器也可以進行迭代,這些直接作用於for迴圈的物件都可以叫做可迭代物件iterable。

乙個實現了iter方法的物件是可迭代的,乙個實現了next方法並且是可迭代的物件是迭代器。

生成器和迭代器

可以直接作用於for迴圈的物件稱為可迭代物件 iterable.可以用isinstance 判斷乙個物件是否是iterable物件。isinstance iterable true isinstance iterable true isinstance 235,iterable false 而生成器...

迭代器和生成器

1 迭代器的概念 print dir 告訴我列表的所有用法 有雙下劃線的所有方法叫做雙下方法,是c語言已經寫好的方法。你可以用不止一種方法呼叫它。列表的用法變集合 set dir 求交集 set dir set dir set dir 求列表,字典,字串它們的用法的交集 他們共同的用法 iterab...

生成器和迭代器

1.iterator 迭代器 舉例 我們對list使用for for i in 1,2,3,4 print i 12 34對string物件使用for for ch in python print ch py thon對字典物件使用for for k in print k yx對檔案使用for fo...