8列表解析_生成器表達式

 

list comprehension,列表解析:

語法:

[返回值 for 元素 in 可迭代對象 if 條件]

 

注:

列表解析沒有elif,如果有多個條件可用多個if或配合orand使用;

 

列表解析是語法糖:

編譯器會優化,不會因爲簡寫而影響效率,反而因優化提高了效率,不僅字節碼更少,而且減少了棧針;

減少程序員工作量,減少出錯;

簡化了代碼,可讀性增強;

 

例:

生成一個列表,元素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)返回110平方的列表?

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位隨機小寫英文字母,請依次生成前100ID的列表?

方一:

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)]

 

注:

asciiamerican standard code for information interchange,美國信息交換標準代碼;

小寫a-z對應ascii碼的97-122

ascii碼錶的0-127常用,0-9,\t,\n,\r,space對應的ascii

chr(),將ascii碼對應的數字轉爲字符;

0-31,12733個控制字符,或通信專用字符;

32-12695個字符;

32,空格;

48-570-9數字;

65-9026個大寫英文字母;

97-12226個小寫英文字母;

8,退格;

9,製表;

10,換行;

13,回車;

 

 

 

generator expression,生成器表達式:

語法:

(返回值 for 元素 in 可迭代對象 if 條件)

列表解析的[]換爲()即可;

返回一個生成器;

 

list comprehension區別:

generator expression是按需計算,或稱惰性求值(延遲計算,python思想),需要的時候才計算值,不需要的時候給個對象(可理解爲中間狀態,是一種可迭代對象);

list comprehension是立即返回值;

預計算和延遲計算,都有應用場景;

 

生成器:

iterable,可迭代對象;

iterator,迭代器;

iterable不一定是iteratoriterator一定是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'

 

生成器表達式和列表解析式的對比:

計算方式,生成器表達式延遲計算,列表解析式立即計算;

內存佔用,單從返回值本身來說,生成器表達式省內存,列表解析式返回新的列表(構造出新的列表,需佔用內存);生成器沒有數據,內存佔用極少,但使用時,雖然一個個返回數據,但合起來佔用的內存也差不多;

計算速度,單從計算時間看,生成器表達式耗時非常短,列表解析式耗時時間長;但是生成器本身並沒有返回任何值,只返回了一個生成器對象;列表解析式構造並返回了一個新的列表;

 1.jpg

 

集合解析式:

語法:

{返回值 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 inin本質上就是在遍歷對象;

 

迭代器:

特殊的對象,一定是可迭代對象,具備可迭代對象的特徵;

通過iter(iterable)把一個可迭代對象封裝成迭代器;

通過next()迭代迭代器對象;

生成器對象,就是迭代器對象;

迭代器不一定是生成器;

 

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章