從一個問題來看解析式,現有以下需求:生成一個列表,元素0-9,對每個元素自增1後求平方返回新列表。app
lst = list(range(10)) lst2 = [] for value in lst: lst2.append((value + 1) ** 2) print(lst2)
看起來很容易理解,可是這種需求居然用了5行代碼!下面來看一下列表解析式的寫法。函數
[ (x+1)**2 for x in range(10)]
看起來很是簡潔,屬於Python的風格!哈哈性能
再來看一下,什麼是列表解析式?在Python中列表解析式是一種語法糖,雖然對看似複雜的代碼進行了簡寫,可是編譯器會進行優化,不會由於簡寫而影響效率,反而由於優化提升了效率。另外還介紹了代碼量,減小了出錯的機會,還簡化了代碼,增長了代碼可讀性。學習
列表解析式的基本語法是以下優化
[ 返回值 for 元素 in 可迭代對象 if 條件]
中括號
將表達式(推導式)括起來elif語句
有這樣的賦值語句 newlist = [ print(i) for i in range(10) ]
,請問newlist打印出來是什麼?code
In [6]: newlist = [ print(i) for i in range(10) ] 0 1 2 3 4 5 6 7 8 9 In [7]: newlist Out[7]: [None, None, None, None, None, None, None, None, None, None]
爲何是None?由於表達式只會將函數的返回值做爲結果,進行添加,因此當返回值是一個函數操做的對象時,必定要注意函數的返回值!對象
有的時候咱們的代碼須要進行兩個或多個循環,列表解析式進階版本能夠知足這種需求哦。它的語法是:ip
[ 返回值 for 元素 in 可迭代對象 if 條件表達式1 if 條件表達式2 ... ] 等同於: for 元素 in 可迭代對象: if 條件表達式1: if 條件表達式2: 返回值 [ 返回值 for 元素 in 可迭代對象1 for 元素 in 可迭代對象2 ... ] 等同於: for 元素1 in 可迭代對象1: for 元素2 in 可迭代對象2: # if 也能夠加條件判斷 返回值[1個或多個]
例子:內存
20之內,既能被2整除,又能被3整除的列表 [ i for i in range(20) if i % 2 == 0 if i % 3 == 0] [(i,j) for i in range(10) for j in range(20) if i < 3 if j > 18] 表示當i小於3時,j大於18時,組成一個元素返回
除了列表解析式之外,Python中還存在集合解析式
、字典解析式
、'元組解析式'
。
可不是什麼元組解析式,這行小字你看不到,可不怪我哦。
{ 返回值 for 元素 in 可迭代對象 if 條件 }
{}
便可20之內,既能被2整除,又能被3整除的集合 { i for i in range(20) if i % 2 == 0 if i % 3 == 0}
注意集合的特性,若是生成了不可hash的元素好比list,那麼是不能生成集合的哦,若是元素重複,集合會去重的哦
{ 返回值(key:value) for 元素 in 可迭代對象 if 條件 }
{}
便可生成一個key爲abcded的字典 {x:y for x in 'abcdef' for y in range(10)}
注意字典的key相同時,後面的賦值會把以前的值覆蓋哦,因此結果是
{'a': 9, 'b': 9, 'c': 9, 'd': 9, 'e': 9, 'f': 9}
若是你是從上倒下看的,那麼你可能會奇怪,說好的元組表達式呢?若是你是直接跳轉過來的,那麼請忽略前面這句話。那什麼是生成器表達式呢?
生成器表達式是按需計算(或者惰性求值、延遲計算)的,只有須要的時候才計算值,而列表解析式是直接返回一個新的列表,生成器是一個可迭代對象
,迭代器
。在使用type命令判斷對象類型時,generator
就表示一個生成器對象
()
便可延遲計算(惰性計算)
只能迭代一次,不能回頭
g = ((i,j) for i in range(10) for j in range(20) if i < 3 if j > 18) print(g) # <generator object <genexpr> at 0x7fca2552b258> for i in g: print(i) # 只能迭代一次,迭代完畢生成器就爲空了哦,
沒錯,用括號括起來的並非元組表達式,而變成了生成器表達式
,它自己因爲惰性計算的特性和其餘解析式有不少不一樣的特性
計算方式
內存佔用
計算速度
遍歷
當咱們須要對數據進行遍歷時,因爲生成器是遍歷一次計算一個返給你,而列表解析式執行完畢後直接返回一個新的列表不須要計算,因此性能要優於生成器表達式。
除了遍歷咱們還能夠經過
next方法
來一次一次的獲取生成器的數據
In [8]: g = ((i,j) for i in range(10) for j in range(20) if i < 3 if j > 18) In [9]: next(g) Out[9]: (0, 19) In [10]: next(g) Out[10]: (1, 19) In [11]: next(g) Out[11]: (2, 19) In [12]: next(g) --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-12-e734f8aca5ac> in <module> ----> 1 next(g) StopIteration: In [13]:
next()能夠理解爲向生成器要一次數據(撥一下生成器),當生成器爲空時,就會提示
StopIteration
異常,for循環幫咱們對StopIteration異常作了處理,尚未學習異常處理的咱們,該怎麼辦呢?其實next方法爲咱們提供了默認值參數
,即從生成器中拿不到數據,就返回指定的默認:next(g[, default])
。
In [13]: g = ((i,j) for i in range(10) for j in range(20) if i < 3 if j > 18) In [14]: next(g, 'None') Out[14]: (0, 19) In [15]: next(g, 'None') Out[15]: (1, 19) In [16]: next(g, 'None') Out[16]: (2, 19) In [17]: next(g, 'None') # 生成器空了,就返回default指定的默認值 Out[17]: 'None' In [18]: next(g, 'None') Out[18]: 'None'
Python2 引入列表解析式,Python2.4引入生成器表達式,Python3 引入集合、字典解析式,並遷移到了Python 2.7,通常來講,應該多用解析式,簡短、高效不過還須要注意的是:
從是否可迭代來看生成器、迭代器、可迭代對象的關係是以下