1. 程式人生 > >python學習筆記(五)--列表生成式、生成器(generator)、yield關鍵字

python學習筆記(五)--列表生成式、生成器(generator)、yield關鍵字

列表生成式

能夠快速的生成一個list

配合 for 迴圈使用,for 迴圈 遍歷出的結果 無需像如下方式生成

>>> for x in range(1,11):
	Li.append(x)

	
>>> Li
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

而是用列表生成式讓這個操作變得更為便捷

>>> [x for x in range(1,11)]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

就是 將 for遍歷出來的變數 x  放到 for 前面,並在 外側加上一個中括號,這樣就可以直接生成一個 list。

同樣,因為 for迴圈支援遍歷以後提取出多個變數,所以列表生成器 也支援多個變數的組裝

如下我們將一個dict 通過便利 組裝成 一個 list

>>> L = {'a':'1','b':'2','c':'3'}
>>> [k +'='+ v for k,v in L.items()]
['a=1', 'b=2', 'c=3']

列表生成式 同樣支援對 遍歷出來的結果進行轉換

>>> L = {'AaAa':'1','BbBb':'2','CcCc':'3'}
>>> [k.lower() +'='+ v for k,v in L.items()]
['aaaa=1', 'bbbb=2', 'cccc=3']

列表生成式 還可以配合 if 來使用

如下提取出 1-10 中 偶數數字

>>> [x for x in range(1,11) if x % 2 == 0]
[2, 4, 6, 8, 10]

列表生成式 還支援 多重迴圈

>>> [x+y for x in "abc" for y in "xyz"]
['ax', 'ay', 'az', 'bx', 'by', 'bz', 'cx', 'cy', 'cz']

生成器(generator) 

由於list有一個致命的缺點,如果元素個數過多,會導致極大的消耗記憶體容量,而且有時我們只需要list中的前幾個元素。

generator 就可以為我們解決這個問題。

上面說了 列表生成式,我們只需要把列表生成式 外側的中括號換成小括號 返回的結果就成 list變成了generator。

然後通過 next(generator) 就可以每呼叫一次 這個方法,就讀取出一個值,類似於java中Iterator的next()方法,其實在python中也有Iterator這個物件,只要是Iterator物件的都可以通過next方法進行迭代。

>>> g = (x for x in "123456789")
>>> next(g)
'1'
>>> next(g)
'2'
>>> next(g)
'3'
>>> next(g)
'4'
>>> next(g)
'5'
>>> next(g)
'6'
>>> next(g)
'7'
>>> next(g)
'8'
>>> next(g)
'9'
>>> next(g)
Traceback (most recent call last):          後面沒有值了會報異常
  File "<pyshell#36>", line 1, in <module>
    next(g)
StopIteration
>>> 

generator 只有在我們想要使用 到某個值得時候,它才會根據邏輯去為我們生成這個值,比如我第一次呼叫next(g),它只為我生成了字串'1',後面的'23456789'都不存在,再呼叫next(g)才會生成 ‘2’,所以它 相對於 列表來說 非常節省記憶體。

但是,顯然這種方式在實際開發中並不適用,一直next()。

我們判斷一下 generator是否可以用for迴圈來遍歷

>>> from collections import Iterator
>>> 
>>> isinstance(g,Iterator)
True

發現是可以的

>>> g = (x+'='+y for x,y in {'a':'1','b':'2','c':'3'}.items())
>>> for x in g:
	print (x)
	if x.find('2'):
		break

	
a=1             

>>> next(g)          
'b=2'                

再說說 generator的另外一種表現形式  (yield關鍵字)

當我們在一個方法中執行到return,如果 return後面還需要計算,那麼計算完以後方法就會執行完畢。

但是如果方法中包含yield關鍵字,那麼它就不再是一個方法了,而是一個generator物件。

即我們需要使用next()才能讓它執行,並且每當遇到yield關鍵字,會打印出yield關鍵字後面的內容,並暫停於當前位置。

當我們再次呼叫next()方法,會從當前位置繼續向下執行,再配到yield關鍵字還是輸出、暫停。

>>> def odd():
	print('1')
	yield 1
	print('2')
	yield 2
	print('3')
	yield 3

	
>>> odd()
<generator object odd at 0x00000000031844F8>
>>> a = odd()
>>> next(a)
1
1
>>> next(a)
2
2
>>> next(a)
3
3
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#76>", line 1, in <module>
    next(a)
StopIteration

再看另外一個案例

>>> def func():
	n = 0
	while True:
		yield (n)
		if n == 10:
			return "done"
		n = n+1

		
>>> func()
<generator object func at 0x00000000031AB390>
>>> a = func()
>>> next(a)
0
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
>>> next(a)
4
>>> next(a)
5
>>> next(a)
6
>>> next(a)
7
>>> next(a)
8
>>> next(a)
9
>>> next(a)
10
>>> next(a)
Traceback (most recent call last):
  File "<pyshell#103>", line 1, in <module>
    next(a)
StopIteration: done
>>> def func():
	n = 0
	while True:
		yield (n)
		if n == 10:
			return "done"
		n = n+1

>>> g = func()
>>> while True:
	try:
		x = next(g)
		print('g:',x)
	except StopIteration as e:
		print('Generator return value:',e.value)
		break

	
g: 0
g: 1
g: 2
g: 3
g: 4
g: 5
g: 6
g: 7
g: 8
g: 9
g: 10
Generator return value: done

可以看出如果通過呼叫next()方法,最後沒有值了,報出StopIteration異常,且我們的方法有返回值,python會將我們的返回值放入這個StopIteration這個物件的value屬性中。