python中的三元表達式,列表解析 和 生成器表達式

三元表達式

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 是一個三元表達式,判斷語句在三元表達式中實現~

-- 全0列表

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])                  # 沒有問題

.................^_^

相關文章
相關標籤/搜索