python中的 3元表達式是對 if...else... 語句的一種簡寫~;這個在不少時候都很是有用,並且能夠使代碼簡單且易於維護。python
x = 3 y = 4 if x > y: res = x else: res = y
上述代碼若使用 3元表達式,if...else...語句能夠簡寫成一行express
x = 4 y = 3 res = x if x > y else y
上述例子中,3元表達式最左邊的 x 和最右邊的 y 能夠寫成任意的表達式app
x = 4 y = 3 res = 'aaa' if x > y else 'bbb'
列表解析(list comprehension),通常會配合 for 循環,以比較優雅的方式生成列表,大大減小代碼量,且加強了代碼的可讀性~ide
s = [] for i in 'hello': s.append(i.upper()) print(s) 輸出結果: ['H', 'E', 'L', 'L', 'O']
上述代碼若使用列表解析,可以使用以下代碼替換,輸出結果一致:函數
s = [i.upper() for i in 'hello'] print(s)
說明:for 循環獲得的每個元素返回給 for 前面的 i 變量,而後執行 upper 函數,將執行結果以列表的形式返回~。相比於 for 循環,列表解析的語法由 c語言實現,性能會有所提高~性能
列表解析中,for 循環後面亦可添加 條件語句,篩選出知足條件的元素:code
lst = [1,2,60,67,34,78,98,70,89] print([i for i in lst if i > 50]) 輸出結果: [60, 67, 78, 98, 70, 89]
總結一下列表解析的語法:對象
[expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ..... for itemN in iterableN if conditionN ]
絕大多數的狀況,列表解析僅使用一層循環,即:索引
[expression for item in iterable if condition]
上面已經給出列表解析的語法,for 循環前面的 expression 能夠是一個變量,也能夠是一個表達式,看以下示例,列表中的×××(int)原樣取出,如果浮點類型(float),則進行四捨五入後取出:內存
a = [1,2,3.2,1.3,5.9] res = [i if isinstance(i, int) else int(round(i)) for i in a] res : [1, 2, 3, 1, 6]
這裏 for 循環前的 expression 是一個三元表達式,判斷語句在三元表達式中實現~
for 循環前的 expression 也能夠是一個 常量,例如要獲取一個固定長度的,且都是某個值的列表:
lst = [0 for i in range(10)] # 長度爲10,全爲0 的列表 lst : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
列表解析多層 for 循環示例,讀取列表中每一個單詞的字母,並生成一個新的列表:
lst = ['hello', 'kitty'] res = [l for word in lst for l in word] res : ['h', 'e', 'l', 'l', 'o', 'k', 'i', 't', 't', 'y']
如上示例可能一會兒難以理解,根據列表解析的語法:
[expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ..... for itemN in iterableN if conditionN ] 相似於 res=[] for item1 in iterable1: if condition1: for item2 in iterable2: if condition2: ...... for itemN in iterableN: if conditionN: res.append(expression)
如上示例使用 for 循環表示:
res = [] for word in lst: for l in word: res.append(l) print(res) 輸出結果: ['h', 'e', 'l', 'l', 'o', 'k', 'i', 't', 't', 'y']
列表解析並無下降代碼的可讀性,且縮小了代碼量、提高了性能,可是若其中出現多層 for 循環嵌套,可能會下降代碼的可讀性,不易於理解~
列表解析會一次性生成全部的數據到內存中,而後生成列表對象,這樣不適用於迭代大量的數據。 而生成器表達式正好解決了這個問題~
生成器表達式的語法與列表解析的語法相似,即外面的中括號 換成括號便可:
語法: (expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ..... for itemN in iterableN if conditionN ) 示例: >>> g = (i for i in range(100)) >>> g <generator object <genexpr> at 0x00000288D8C9A308>
若使用生成器表達式,全部的數據不會一次性所有加載到內存中,而是按照從前向後的順序,用到一個加載一個。當數據量比較大時,更節省內存~
import time start_time = time.time() g = (i for i in range(100000000)) stop_time = time.time() print('run time is %s' % (stop_time - start_time)) print(next(g)) print(next(g)) print(next(g)) 輸出結果: run time is 0.0 # 獲得生成器 g 的用時~ 0 1 2
一樣的數據量使用列表解析,會消耗至關長的時間,如果再加幾個0,程序可能就會卡住:
import time start_time = time.time() lst = [i for i in range(100000000)] stop_time = time.time() print('run time is %s' % (stop_time - start_time)) lst_iter = lst.__iter__() print(next(lst_iter)) print(next(lst_iter)) print(next(lst_iter)) 輸出結果: run time is 5.407538890838623 # 生成列表的時長 0 1 2
固然生成器表達式也有缺點,因爲生成器表達式返回的是一個生成器,因此若要迭代全部的元素,只能從前日後挨個迭代;而列表解析返回的是列表,能夠根據索引當即返回指定位置的元素~
gen = (i for i in range(100)) # print(gen[10]) # 錯誤 lst = [i for i in range(100)] print(lst[10]) # 沒有問題
.................^_^