首先在了解解析式之前,我們先來看乙個列子:乙個列表,元素是0-9,列表中的每個值自增1,該如何實現:
方法一:遍歷列表,對其元素進行加1操作後放到乙個新的列表中
1 lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]23for index, i in
enumerate(lst):
4 lst[index] += 1
5print(lst)
方法二:通過map函式來實現
a = map(lambda x:x+1, lst)(a)for x in
a:
print(x)
方法三:通過列表解析式,一行搞定
1 lst2 = [x+1 for x inlst]
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(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))23for x in
generator_demo:
4print(x)
通過這種方法來迭代它的值就不會丟擲stopiteration的錯誤了。
這種建立生成器的寫法固然簡單,但是如果是乙個演算法邏輯比較複雜的時候,就不適合通過這種簡單的寫法來建立生成器了,我們可以通過函式的形式來建立生成器,例如著名的斐波那契數列:
1deffib(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關鍵字來定義:
1deffib(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來實現在單執行緒模式下實現併發運算的效果:
1import
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...