1. 程式人生 > 實用技巧 >奇技淫巧,還是正統功夫? - Python推導式最全用法

奇技淫巧,還是正統功夫? - Python推導式最全用法

前言

本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,如有問題請及時聯絡我們以作處理。

PS:如有需要Python學習資料的小夥伴可以加點選下方連結自行獲取

python免費學習資料以及群交流解答點選即可加入


1.Pythonic - 很Python

寫一段程式碼生成1到100之間的數字的平方的列表,答案是:

1,4,9,16...

如果你這樣寫,你就不Pythonic了:

nums = []
for i in range(1,101):
    nums.append(i*i)
print(nums)

正確的寫法是使用Python的推導式:

nums = [i*i for i in range(1,101)]

2.帶條件的推導式

生成一個列表,包含1到100之間是3的倍數的數字的方法:

9,36,81...

程式碼:

nums = [i*i for i in range(1,101) if i%3==0]

3.帶條件的表示式

生成一個列表,如果是3的倍數就用平方,否則就用是數字本身:

1,2,9,4,5,36...

程式碼:

nums = [i*i if i%3==0 else i for i in range(1,101)]

結合上面的3個例子,來看一下推導式總結:

  • 推導式從一個可列舉資料(列表,元組,集合,字典等)推匯出一個列表。也可以推匯出生成器,集合或字典。
  • 推導式可以加推導條件,只對符合條件的元素推導
  • 要推匯出的元素使用表示式生成,可以用if else生成不同元素
[表示式 if 表示式條件 else 分支 for i in 序列 if 推導條件]

4.使用函式

如果推導條件或者表示式特別複雜怎麼辦?可以使用函式。

推導所有1-100之間的所有質數:2,3,5,7...

def is_prime(num):
    if num == 1:
        return False  
    for i in range(2,num):
       if (num % i) == 0:
           return False
    else:
       return True

p_nums = [i for i in range(1,100) if is_prime(i)]
print(p_nums)

把推導的條件放在函式中,既可以應對複雜的條件,又可以利用推導式的簡潔寫法。

同理,如果生成推導結果的過程很複雜,也可以把邏輯放到函式中。

推導1900到2021年之間所有的年份,標記出閏年,生成結果:

1900, 1901, 1902, 1903, '閏1904'

程式碼:

def is_run(year):
    if (year % 4) == 0:
       if (year % 100) == 0:
           if (year % 400) == 0:
               return True   # 整百年能被400整除的是閏年
           else:
               return False
       else:
           return True       # 非整百年能被4整除的為閏年
    else:
       return False 

ryears = [f'閏{y}' if is_run(y) else y for y in range(1900, 2021)]    
print(ryears)

5.巢狀表示式 - 不推薦使用

從2000年到2021年,生成每個月份:'2000年:1月', '2000年:2月', '2020年:3月', ..., '2021年:12月'

monthes = [f'{y}年:{m}月' for y in range(2000, 2022) for m in range(1,13) ]

這裡有兩個for迴圈,類似於:

monthes = []
for y in range(2000, 2022):
    for m in range(1,13):
        monthes.append(f'{y}年:{m}月')

6.推導巨大的列表 - 不要這麼幹!

推匯出1到100億之間的數字的平方,程式碼如下:

nums = [i*i for i in range(1,10000000000)]

但是這段程式碼很可能會卡死你的電腦,除非你的電腦是超級計算機。因為它要在記憶體中做100億次計算,然後儲存這100億個數字。

7.使用生成器

這種情況下,我們應該使用推導生成器,用法很簡單:

  • 把方括號改成圓括號就可以了
nums = (i*i for i in range(1,10000000000))
print(nums)
print(next(nums))
print(next(nums))
print(next(nums))

打印出來是一個生成器:

<generator object <genexpr> at 0x7fa0b422feb0>
1
4
9

這是一個生成器,它不會一次性生成100億個數字,只有呼叫next()的時候,它才會生成一個新的,返回給你。也就是說,同一個時間,只儲存一個數字。

8.推導字典

推導字典的方式和推導列表很相似,只不過:

  • 使用大括號
  • 使用鍵值對
    推導一個包含數字和數字平方組成的字典,結果是這樣的:
{1: 1, 2: 4, 3: 9, ..., 100: 10000}

程式碼:

nums_dict = {n:n*n for n in range(1,101)}
print(nums_dict)

反過來,平方在前面,數字在後面:

nums_dict = {n*n:n for n in range(1,101)}
print(nums_dict)

給下面的字典按照分數排序:

{'麥叔':59, '張三':87, 'FGA':78, '石石':100, '莫名':90}

排序結果:

{'石石': 100, '莫名': 90, '張三': 87, 'FGA': 78, '麥叔': 59}

程式碼:

scores = {'麥叔':59, '張三':87, 'FGA':78, '石石':100, '莫名':90}
sored_scores = {item[0]:item[1] for item in sorted(scores.items(), key=lambda item:item[1], reverse=True)}
print(sored_scores)

1.先把字典scores變成一個元組列表:scores.items()
2.用sorted函式給元組列表排序:sorted(scores.items(), key=lambda item:item[1], reverse=True)
3.排序過程用lambda指定使用元組的第二列排序:key=lambda item:item[1]。預設是是第一列。
4.指定倒著排序,也就是分數高的在前面:reverse=True
5.使用推導式,把排好序的元組列表,生成一個新的排好序的字典:{item[0]:item[1] for item in ... }

9.推導集合Set

推導集合的方式和列表是一樣的,區別在於:

1.使用大括號,類似於推導字典,但它是單個元素,而不是鍵值對。
2.集合會自動過濾掉重複的元素。
下面的名字列表,去掉前後空格後去掉重複的名字:

[ '麥叔', '張三', ' 麥叔 ', 'FGA ', '張小三', 'FGA', '石石',' 莫名','莫名' ]

推導結果:

{'石石', 'FGA', '張小三', '莫名', '張三', '麥叔'}

程式碼:

names = [ '麥叔', '張三', ' 麥叔 ', 'FGA ', '張小三', 'FGA', '石石',' 莫名','莫名' ]
new_names = {n.strip() for n in names}
print(new_names)