跳到主要內容

[Python教學]Python Comprehension語法應用教學

Photo by Jason Strull on Unsplash
相信在學Python程式語言的朋友都知道,Python語法簡單易學且非常簡潔,今天要來介紹的Comprehension即是PythonPythonic語法之一,可以運用在任何可疊代的物件(Iterable Object)上,只要一行程式碼即可完成多行的任務,讓我們的程式碼簡潔及增加可讀性。

透過今天的教學,您將可以學到Python Comprehension如何應用在以下幾個重要的物件(Object)上,並且有能力將現有程式碼改寫為Python Comprehension語法。
  • List Comprehension
  • Set & Dictionary Comprehension
  • Generator Expression

一、List Comprehension

串列(List)Comprehension的語法包含三個部分,說明如下:

[expression for item in iterable]

  • expression:可以是 item 或運算式。
  • item:接收可疊代的物件(Iterable Object)元素。
  • iterable:可疊代的物件(Iterable Object)。
通常要建立一個串列(List),我們可以透過for迴圈的方式,如下範例:

numbers = []
for x in range(10):
    numbers.append(x * 3)

print(numbers)
執行結果
如果透過串列(List)Comprehension來進行改寫的話,只需要一行即可達到相同的執行結果,如下範例:

numbers = [x * 3 for x in range(10)]
print(numbers)
x * 3 就是串列(List)Comprehension中的運算式(expression),而 x 是接收可疊代的物件(Iterable Object)變數,最後就是可疊代的物件(Iterable Object) range(10) 。透過for迴圈的方式讀取元素值,並且乘以3來建立串列(List),語法是不是非常簡潔~

如果我們要在串列(List)Comprehension中利用條件判斷來篩選元素時,則可以使用下列語法:

[expression for item in iterable (if condition)]

延伸上面的範例,當 x 大於4的時候,我們才乘以3的動作,串列(List)Comprehension的寫法如下範例:

numbers = [x * 3 for x in range(10) if x > 4]
print(numbers)
執行結果
另外,串列(List)元素的運算篩選我們Python Lambda Function應用技巧分享文章中有介紹到可以利用Python的內建函式map()filter()等,其中透過了Lambda函式來達成,而串列(List)Comprehension語法同樣也可以實作,我們來比較一下寫法吧。

首先,map()函式可以將特定運算式套用至可疊代的物件(Iterable Object)元素,如下範例:

numbers = [50, 2, 12, 30, 27, 4]
result = list(map(lambda x: x * 2, numbers))
print(result)  #執行結果:[100, 4, 24, 60, 54, 8]
map()函式利用Lambda函式來進行元素的運算,最後透過list()函式來轉型成串列(List)。而串列(List)Comprehension可以改寫成:

numbers = [50, 2, 12, 30, 27, 4]
result = [number * 2 for number in numbers]
print(result)  #執行結果:[100, 4, 24, 60, 54, 8]
我們再來看一個例子,filter()函式可以幫我們篩選可疊代的物件(Iterable Object)元素,如下範例:

numbers = [50, 2, 12, 30, 27, 4]
result = list(filter(lambda x: x > 10, numbers))
print(result)  #執行結果:[50, 12, 30, 27]
在串列(List)Comprehension中則可以改寫為:

numbers = [50, 2, 12, 30, 27, 4]
result = [number for number in numbers if number > 10]
print(result)  # 執行結果:[50, 12, 30, 27]
在此範例中,我們將條件判斷擺在後面來篩選可疊代的物件(Iterable Object)元素,那如果要依據條件來"改變"串列(List)中的值時,則要把條件判斷移至前方,如下範例:

numbers = [50, 2, 12, 30, 27, 4]
result = [number if number > 10 else 0 for number in numbers]
print(result)  # 執行結果:[50, 0, 12, 30, 27, 0]

範例中透過條件判斷將串列(List)中小於等於10的值修改為0,而大於10的則維持原值

Python Comprehension語法Lambda函式一樣,適當的使用可以讓程式碼簡潔且可讀性佳,避免撰寫過於複雜的邏輯,否則只會讓未來維護時不易修改。

二、Set & Dictionary Comprehension

集合(Set)Comprehension的用法和串列(List)Comprehension幾乎一樣,不同的地方是集合(Set)使用 {} 符號,並且其中的元素不會重覆,如下範例:

titles = "Learn Code With Mike"
result = {letter for letter in titles if letter == "e"}
print(result)  # 執行結果:{'e'}
從範例中可以看到 titles 中符合條件的 e 字母有3個,但是集合(Set)只會顯示1個。

另外,字典(Dictionary)Comprehension和集合(Set)Comprehension同樣使用 {} 符號,不同的是字典(Dictionary)的每個元素由鍵(Key)與值(Value)構成,如下範例:

titles = "Python"
result = {index: letter for index, letter in enumerate(titles)}
print(result)
執行結果
範例中利用enumerate()函式回傳可疊代的物件(Iterable Object)元組(Tuple),再透過Unpacking的方式取得鍵(index)與值(letter) ,詳細的觀念可以參考Python Unpacking實用技巧分享

三、Generator Expression

各位一定會想說,那有元組(Tuple)Comprehension嗎?我們依照上面的原則來撰寫如下範例:

result = (number * 2 for number in range(10))
print(result)
執行結果
從執行結果可以看到,我們得到了一個Generator物件(Object),這是什麼呢?

Generator物件(Object)具有延遲的特性,也就是說它不會把所有資料都儲存在記憶體中,而是透過迴圈進行讀取時,來產生值。所以Generator物件(Object)適用於處理非常龐大的資料集,甚至無限個資料的情況。如果透過串列(List)或元組(Tuple)等其它物件來處理時,會將所有資料都儲存在記憶體中,這時候就可以想像將會耗盡記憶體資源。

假設我們將上面範例中的 range(10) 調整為 range(20000),來模擬要處理的資料集非常龐大,接著引用sys模組中的getsizeof()函式(Function),來取得串列(List)Generator物件(Oject)各佔用了多少記憶體空間,如下範例:

from sys import getsizeof

list_result = [number * 2 for number in range(20000)]
print("List: ", getsizeof(list_result))

generator_result = (number * 2 for number in range(20000))
print("Generator: ", getsizeof(generator_result))
執行結果
可以看到串列(List)占用了89008Bytes,而Generator物件(Object)只佔用了56Bytes,省下了不少記憶體空間。但是也需要特別注意,由於Generator物件(Object)不像其它物件如串列(List)等,把所有資料都儲存在記憶體中,所以是無法得知Generator物件(Object)的資料個數,如下範例:

list_result = [number * 2 for number in range(20000)]
print("List: ", len(list_result))

generator_result = (number * 2 for number in range(20000))
print("Generator: ", len(generator_result))
執行結果
可以看到我們可以取得串列(List)的資料個數,而無法取得Generator物件(Object)的資料個數。

四、小結

以上就是Python Comprehension語法的介紹,可以看到單行就可以執行許多的任務,非常Pythonic的語法,希望大家有學起來。在練習的過程中如果有碰到任何問題歡迎留言分享。

如果您喜歡我的文章,請幫我按五下Like(使用GoogleFacebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。


有想要看的教學內容嗎?歡迎利用以下的Google表單讓我知道,將有機會成為教學文章,分享給大家😊

你可能有興趣的文章









留言

  1. 很感謝那麼清楚的解析與教學,目前為程式新手 有一堂課程稍微提到Python Comprehension 但並沒有說明太多 經過網主的分享 學習到不少 (還有一些函式並沒學過 也順帶了解了 真的很實用 ~!! : )

    回覆刪除

張貼留言