list comprehension,列表解析:
語法:
[返回值 for 元素 in 可迭代對象 if 條件]
注:
列表解析沒有elif,如果有多個條件可用多個if或配合or或and使用;
列表解析是語法糖:
編譯器會優化,不會因爲簡寫而影響效率,反而因優化提高了效率,不僅字節碼更少,而且減少了棧針;
減少程序員工作量,減少出錯;
簡化了代碼,可讀性增強;
例:
生成一個列表,元素0-9,對每一個元素自增1後求平方,返回新列表;
[(i+1)**2 for i in range(0,10)]
例:
獲取10以內的偶數,比較執行效率;
方一:
[i for i in range(0,10) if i % 2 == 0]
方二:
even = []
for i in range(10):
if not i % 2: #常用not這種寫法,同if i % 2 == 0:
even.append(i)
print(even)
例:
[0 for _ in range(10)]
[[0] for _ in range(10)]
習題:
1、有這樣的賦值語句:newlist=[print(i) for i in range(10)],newlist的元素打印出的是什麼?
In [3]: newlist=[print(i) for i in range(5)]
0
1
2
3
4
In [4]: newlist
Out[4]: [None, None, None, None, None] #print(i)是表達式的結果或函數計算的結果,print(i)輸出到屏幕了,該列表解析沒有返回值,即最後生成指定個數的None
2、獲取20以內的偶數?如果是3的倍數也打印?
In [6]: [i for i in range(20) if not i%2]
Out[6]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
In [7]: [i for i in range(20) if not i%2 or not i%3] #list comprehension沒有elif,多個條件用多個if或配合or,and使用
Out[7]: [0, 2, 3, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18]
3、獲取20以內既能被2整除又能被3整除的數?
方一:
In [7]: [i for i in range(20) if not i%2 and not i%3]
Out[7]: [0, 6, 12, 18]
方二:
In [8]: [i for i in range(20) if not i%2 if not i%3]
Out[8]: [0, 6, 12, 18]
列表解析進階:
[expr for item in iterable if cond1 if cond2]
等價於
ret=[]
for item in iterable:
if cond1:
if cond2:
ret.append(expr)
[expr for i in iterable1 for j in iterable2]
等價於
ret=[]
for i in iterable1:
for j in iterable2:
ret.append(expr)
例:
In [10]: [(i,j) for i in 'abc' for j in range(3)]
Out[10]:
[('a', 0),
('a', 1),
('a', 2),
('b', 0),
('b', 1),
('b', 2),
('c', 0),
('c', 1),
('c', 2)]
In [11]: [[i,j] for i in 'abc' for j in range(3)]
Out[11]:
[['a', 0],
['a', 1],
['a', 2],
['b', 0],
['b', 1],
['b', 2],
['c', 0],
['c', 1],
['c', 2]]
In [12]: [{i:j} for i in 'abc' for j in range(3)]
Out[12]:
[{'a': 0},
{'a': 1},
{'a': 2},
{'b': 0},
{'b': 1},
{'b': 2},
{'c': 0},
{'c': 1},
{'c': 2}]
習題:
(1)如下語句的輸出?
In [17]: [(i,j) for i in range(7) for j in range(20,25) if i>4 if j>23]
Out[17]: [(5, 24), (6, 24)]
In [18]: [(i,j) for i in range(7) if i>4 for j in range(20,25) if j>23]
Out[18]: [(5, 24), (6, 24)]
In [19]: [(i,j) for i in range(7) for j in range(20,25) if i>4 and j>23] #常用此種
Out[19]: [(5, 24), (6, 24)]
(2)返回1到10平方的列表?
In [20]: [i**2 for i in range(1,11)]
Out[20]: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
(3)lst=[1,4,9,16,2,5,10,15],生成一個新列表,要求新列表元素是lst相鄰兩項之和?
lst = [1,4,9,16,2,5,10,15]
[lst[i]+lst[i+1] for i in range(len(lst)-1)]
(4)打印九九乘法表?
[print('{}*{}={:<3}{}'.format(j,i,i*j,'\n' if i==j else ''),end='') for i in range(1,10) for j in range(1,i+1)]
(5)'0001.abadicddus'是ID格式,要求ID格式以點號分割,左邊是4位從1開始的整數,右邊是10位隨機小寫英文字母,請依次生成前100個ID的列表?
方一:
import random
['{:04}.{}'.format(i,''.join([chr(random.randint(97,122)) for _ in range(10)])) for i in range(1,101)]
方二:
import random
import string
['{:04}.{}'.format(i,''.join([random.choice(string.ascii_lowercase) for _ in range(10)])) for i in range(1,101)]
方三:
import random
['{:04}.{}'.format(i,''.join([random.choice(bytes(range(97,123)).decode()) for _ in range(10)])) for i in range(1,101)]
注:
ascii,american standard code for information interchange,美國信息交換標準代碼;
小寫a-z對應ascii碼的97-122;
ascii碼錶的0-127常用,0-9,\t,\n,\r,space對應的ascii;
chr(),將ascii碼對應的數字轉爲字符;
0-31,127,33個控制字符,或通信專用字符;
32-126,95個字符;
32,空格;
48-57,0-9數字;
65-90,26個大寫英文字母;
97-122,26個小寫英文字母;
8,退格;
9,製表;
10,換行;
13,回車;
generator expression,生成器表達式:
語法:
(返回值 for 元素 in 可迭代對象 if 條件)
列表解析的[]換爲()即可;
返回一個生成器;
和list comprehension區別:
generator expression是按需計算,或稱惰性求值(延遲計算,python思想),需要的時候才計算值,不需要的時候給個對象(可理解爲中間狀態,是一種可迭代對象);
list comprehension是立即返回值;
預計算和延遲計算,都有應用場景;
生成器:
iterable,可迭代對象;
iterator,迭代器;
iterable不一定是iterator,iterator一定是iterable;
next(),用next()方法測試是否是iterator;
在迭代時最好用for控制,如果直接用next()要控制好邊界,否則拋異常;
迭代完後,不能回頭;
生成器總結:
延遲計算;
返回迭代器,可以迭代;
從前到後走完一遍後,不能回頭;
列表解析總結:
立即計算;
返回的不是迭代器,返回可迭代對象列表;
從前到後走完一遍後,可重新回頭迭代;
例:
In [1]: [i for i in range(5)]
Out[1]: [0, 1, 2, 3, 4]
In [2]: (i for i in range(5))
Out[2]: <generator object <genexpr> at 0x7fc6440cc9e8>
In [3]: for x in (i for i in range(5)):
...: print(x)
...:
0
1
2
3
4
In [11]: g=('{:04}'.format(i) for i in range(1,4))
In [12]: next(g)
Out[12]: '0001'
In [13]: next(g)
Out[13]: '0002'
In [14]: next(g)
Out[14]: '0003'
In [15]: next(g)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-15-e734f8aca5ac> in <module>()
----> 1 next(g)
StopIteration:
In [16]: g=('{:04}'.format(i) for i in range(1,4)) #iterator最好用for控制
In [17]: for i in g:
...: print(i)
...:
0001
0002
0003
In [23]: lc=['{:04}'.format(i) for i in range(5)]
In [25]: for x in lc:
...: print(x)
...: print('############')
...: for x in lc:
...: print(x)
...:
0000
0001
0002
0003
0004
############
0000
0001
0002
0003
0004
習題:
it=(print('{}'.format(i+1)) for i in range(2))
first=next(it)
second=next(it)
val=first+second
val的值是什麼? #報錯,print()語句是輸出到控制檯,該生成器返回值爲None
val=first+second語句之後,能否再次next(it)? #不能
In [18]: it=(print('{}'.format(i+1)) for i in range(2))
In [19]: type(it)
Out[19]: generator
In [20]: first=next(it)
1
In [21]: second=next(it)
2
In [22]: val=first+second
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-22-663c3b91df51> in <module>()
----> 1 val=first+second
TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType'
生成器表達式和列表解析式的對比:
計算方式,生成器表達式延遲計算,列表解析式立即計算;
內存佔用,單從返回值本身來說,生成器表達式省內存,列表解析式返回新的列表(構造出新的列表,需佔用內存);生成器沒有數據,內存佔用極少,但使用時,雖然一個個返回數據,但合起來佔用的內存也差不多;
計算速度,單從計算時間看,生成器表達式耗時非常短,列表解析式耗時時間長;但是生成器本身並沒有返回任何值,只返回了一個生成器對象;列表解析式構造並返回了一個新的列表;
集合解析式:
語法:
{返回值 for 元素 in 可迭代對象 if 條件}
{}
立即返回一個集合;
例:
In [26]: {(x,x+1) for x in range(5)}
Out[26]: {(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)}
In [27]: {[x] for x in range(5)}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-27-a39ffa943c7e> in <module>()
----> 1 {[x] for x in range(5)}
<ipython-input-27-a39ffa943c7e> in <setcomp>(.0)
----> 1 {[x] for x in range(5)}
TypeError: unhashable type: 'list'
字典解析式:
語法:
{返回值 for 元素 in 可迭代對象 if 條件}
{},用key:value形式;
立即返回一個字典;
例:
In [28]: {x:(x,x+1) for x in range(5)}
Out[28]: {0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5)}
In [29]: {x:[x,x+1] for x in range(5)}
Out[29]: {0: [0, 1], 1: [1, 2], 2: [2, 3], 3: [3, 4], 4: [4, 5]}
In [30]: {[x]:[x,x+1] for x in range(5)}
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-30-32f94dcaf39f> in <module>()
----> 1 {[x]:[x,x+1] for x in range(5)}
<ipython-input-30-32f94dcaf39f> in <dictcomp>(.0)
----> 1 {[x]:[x,x+1] for x in range(5)}
TypeError: unhashable type: 'list'
In [31]: {(x,):[x,x+1] for x in range(5)}
Out[31]: {(0,): [0, 1], (1,): [1, 2], (2,): [2, 3], (3,): [3, 4], (4,): [4, 5]}
In [32]: {chr(0x41+x):x**2 for x in range(5)}
Out[32]: {'A': 0, 'B': 1, 'C': 4, 'D': 9, 'E': 16}
In [33]: {str(x):y for x in range(3) for y in range(4)} #等價於如下
Out[33]: {'0': 3, '1': 3, '2': 3}
In [34]: ret={}
In [36]: for i in range(3):
...: for j in range(4):
...: ret[str(i)]=j
...:
...:
In [37]: ret
Out[37]: {'0': 3, '1': 3, '2': 3}
python2引入列表解析式;
python3引入生成器表達式;
python3引入集合解析式、字典解析式、並遷移到了2.7;
一般來說,要多應用解析式、簡短、高效;
如果一個解析式非常複雜,難以讀懂,要考慮拆解成for循環;
生成器和迭代器是不同的對象,但都是可迭代對象;
iter(iterable),將一個可迭代對象封裝成一個迭代器;
next(iterator),取元素,對一個迭代器取下一個元素,如果元素全部取完,再next()會拋StopIteration異常;
可迭代對象:
能夠通過迭代一次次返回不同元素的對象,所謂相同不是指值是否相同,而是元素在容器中是否是同一個,如list中值可重複;
可以迭代,但是未必有序,未必可索引;
可迭代對象有,list,tuple,string,bytes,bytearray,range,set,dict,iterator等;
可用成員運算符in,not in,in本質上就是在遍歷對象;
迭代器:
特殊的對象,一定是可迭代對象,具備可迭代對象的特徵;
通過iter(iterable)把一個可迭代對象封裝成迭代器;
通過next()迭代迭代器對象;
生成器對象,就是迭代器對象;
迭代器不一定是生成器;