列表解析式(List Comprehension)


1、列表解析 List Comprehension
  舉例:生成一個列表,元素0~9,對每一個元素自增1后求平方返回新列表

# 傳統做法
lst = list(range(10))
newlist = []
for i in range(len(lst)-1):
    newlist.append((i + 1) ** 2)
print(newlist)

執行結果:
[1, 4, 9, 16, 25, 36, 49, 64, 81]
# 使用列表解析式
lst = list(range(10))
print([((i + 1) ** 2) for i in lst])

執行結果:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

  語法
    [返回值 for 元素 in 可迭代對象 if 條件]
    使用中括號[],內部是for循環,if條件語句可選
    返回一個新的列表

  列表解析式是一種語法糖
    編譯器會優化,不會因為簡寫而影響效率,反而因優化提高了效率
    減少程序員工作量,減少出錯
    簡化了代碼,但可讀性增強

# 舉例1:獲取10以內的偶數
print([x for x in range(10) if x % 2 == 0])

執行結果:
[0, 2, 4, 6, 8]
# 舉例2:newlist = [print(i) for i in range(10)],請問打印出什么? newlist 打印出來是什么?
newlist = [print(i) for i in range(10)]
print(newlist)    #print函數返回值為None

執行結果:
0
1
2
3
4
5
6
7
8
9
[None, None, None, None, None, None, None, None, None, None]
# 舉例3:獲取20以內的偶數,如果同時3的倍數也打印
# 列表解析式不允許存在else語句
print([i for i in range(20) if i % 2 == 0 or i % 3 == 0]) 執行結果: [0, 2, 3, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18]

 

2、列表解析進階
  [expr for item in iterable if cond1 if cond2]
  [expr for i in iteravle1 for j in iterable2]    #兩層循環

# 舉例1:
print
([(i,j) for i in range(7) if i > 4 for j in range(20,25) if j > 23]) print([(i,j) for i in range(7) for j in range(20,25) if i > 4 if j > 23]) print([(i,j) for i in range(7) for j in range(20,25) if i > 4 and j > 23]) 執行結果: [(5, 24), (6, 24)] [(5, 24), (6, 24)] [(5, 24), (6, 24)]
# 舉例2:返回1-10平方的列表
[(x ** 2) for x in range(1,11)]
# 舉例3:有一個列表lst= [1,4,9,16,2,5,10,15], 生成一一個新列表,要求新列表元素是Ist相鄰2項的和
lst= [1,4,9,16,2,5,10,15]
newlist = [(lst[i] + lst[i+1]) for i in range(len(lst) - 1)]
print(newlist)

 

3、生成器表達式 Generator expression
  語法:
    (返回值 for 元素 in 可迭代對象 if 條件)
    列表解析式的中括號換成小括號就行了
    返回一個生成器

  和列表解析式的區別:
    生成器表達式是按需計算(或稱惰性求值、延遲計算),需要的時候才計算值
    列表解析式是立即返回值

  生成器:
    可迭代對象
    迭代器

g = ("{:04}".format(i) for i in range(1,11))
print(g)
next(g)
for i in g:
    print(i)

執行結果:
<generator object <genexpr> at 0x000002771C5B3548>
0002
0003
0004
0005
0006
0007
0008
0009
0010

  總結:
    延遲計算
    返回迭代器,可以迭代
    從前到后走完一遍,不能回頭

  而列表:
    立即計算
    返回的不是迭代器,返回可迭代對象列表
    從前到后走完一遍,可以重新回頭迭代

# 思考:
it = (print("{}".format(i+1) for i in range(2))) first = next(it) #1 second = next(it) #2 val = first + second 執行結果: <generator object <genexpr> at 0x000001B2AE19E548> Traceback (most recent call last): ...... first = next(it) TypeError: 'NoneType' object is not an iterator

# 因為 first,second 返回值為None
# 思考:
it = (x for x in range(10) if x % 2)    # x % 2 = 1 輸出
first = next(it)     # 1
second = next(it)    # 3
val = first + second # 4
print(val)

執行結果:
4

# first,second 的返回值為 1,3

 

  生成器表達式和列表解析式的對比
  1> 計算方式
    生成器表達式延遲計算,列表解析式立即計算
  2> 內存占用
    單從返回值本身來說,生成器表達式省內存,列表解析式返回新的列表
    生成器沒有數據,內存占用極少,它是使用時一個個返回數據。如果將這些返回的數據合起來占用的內存也和列表解析式差不多。但是,它不需要立即占用這么多內存。
    列表解析式構造新的列表需要立即占用內存,不管你是否立即使用這么多數據
  3> 計算速度
    單看計算時間看,生成器表達式耗時非常短,列表解析式耗時長
    但是生成器本身並沒有返回任何值,只返回了一個生成器對象
    列表解析式構造並返回了一個新的列表,所以看起來耗時了

 

4、集合解析式
  語法:
    {返回值 for 元素 in 可迭代對象 if 條件}
    列表解析式的中括號換成大括號{}就行了
    立即返回一個集合
  用法:

print({(x, x + 1) for x in range(10)})

執行結果:
{(0, 1), (1, 2), (7, 8), (6, 7), (4, 5), (5, 6), (8, 9), (9, 10), (2, 3), (3, 4)}
print({[x] for x in range(10)})    #新建一個集合,集合的元素要求可哈希,執行錯誤

 

 

5、字典解析式
  語法:
    {返回值 for 元素 in 可迭代對象 if 條件}
    列表解析式的中括號換成大括號{}就行了
    使用key:value形式
    立即返回一個字典
  用法:

print({x:(x,x+1) for x in range(10)})

執行結果:
{0: (0, 1), 1: (1, 2), 2: (2, 3), 3: (3, 4), 4: (4, 5), 5: (5, 6), 6: (6, 7), 7: (7, 8), 8: (8, 9), 9: (9, 10)}

 

print({x:[x,x+1] for x in range(10)})

執行結果:
{0: [0,
1], 1: [1, 2], 2: [2, 3], 3: [3, 4], 4: [4, 5], 5: [5, 6], 6: [6, 7], 7: [7, 8], 8: [8, 9], 9: [9, 10]}

 

print({(x,):[x,x+1] for x in range(10)})

 

print({[x]:[x,x+1] for x in range(10)})    #key:[x]不可哈希

 

print({chr(0x41+x):x**2 for x in range(10)})

執行結果:
{'A': 0, 'B': 1, 'C': 4, 'D': 9, 'E': 16, 'F': 25, 'G': 36, 'H': 49, 'I': 64, 'J': 81}

 

print({str(x):y for x in range(3) for y in range(4)})    #覆蓋

執行結果:
{'0': 3, '1': 3, '2': 3}

 

 

6、總結:
  Python2弓|入列表解析式
  Python2.4引入生成器表達式
  Python3引入集合、字典解析式,並遷移到了2.7
  一般來說,應該多應用解析式,簡短、高效
  如果一個解析式非常復雜,難以讀懂,可以考慮拆解成for循環
  生成器和迭代器是不同的對象,但都是可迭代對象
  可迭代對象范圍更大,都可以使用for循環遍歷


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM