# 一次了解 Python Comprehension 的用法

> *Photo by Chris Ried on [Unsplash](https://unsplash.com/photos/a-computer-screen-with-a-bunch-of-code-on-it-ieic5Tq8YMk)*
今天是要來推薦各位讀者老爺們一個有趣的Python小工具,就是 comprehension 啦~
Python 的 comprehension 是一種簡潔且優雅的方式來建立列表、集合、字典和生成器。理解和掌握 comprehension 可以讓你的代碼更簡潔且具可讀性。本文將詳細介紹列表推導式、集合推導式、字典推導式和生成器推導式。
## 列表推導式 (List Comprehension)
列表推導式用於建立新的列表,語法非常簡潔。基本語法如下:
```python
[expression for item in iterable if condition]
```
* **expression** 是應用於每個項目的表達式。
* **item** 是從 **iterable** 中取出的每個元素。
* **condition** 是可選的,它過濾掉那些不滿足條件的元素。
### 範例
1. 建立一個 **1** 到 **10** 的列表
```python
squares = [item for item in range(1, 11)]
print(squares) # 輸出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```
2. 建立一個只包含偶數的列表
```python
even_squares = [item for item in range(1, 11) if item % 2 == 0]
print(even_squares) # 輸出: [2, 4, 6, 8, 10]
```
## 集合推導式 (Set Comprehension)
集合推導式的語法與列表推導式類似,只是使用大括號 **{}**。它用於建立集合,集合中的元素是唯一的。
```python
{expression for item in iterable if condition}
```
### 範例
1. 建立一個包含唯一平方數的集合:
```python
unique_squares = {x**2 for x in range(10)}
print(unique_squares) # 輸出: {0, 1, 64, 4, 36, 9, 16, 81, 49, 25}
```
## 字典推導式 (Dictionary Comprehension)
字典推導式用於建立字典,語法如下:
```python
{key: value for item in iterable if condition}
```
* **key** 和 **value** 是應用於每個項目的表達式。
### 範例
1. 建立一個數字及其平方的字典:
```python!
squares_dict = {x: x**2 for x in range(10)}
print(squares_dict) # 輸出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
```
2. 建立一個只包含偶數及其平方的字典:
```python
even_squares_dict = {x: x**2 for x in range(10) if x % 2 == 0}
print(even_squares_dict) # 輸出: {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}
```
## 生成器推導式 (Generator Expression)
生成器推導式用於建立生成器,語法與列表推導式類似,只是使用小括號 **()**。生成器不會立即生成所有元素,而是根據需要逐個生成,這對於處理大量數據非常有用。
```python
(expression for item in iterable if condition)
```
### 範例
1. 建立一個生成器,生成平方數:
```python
squares_generator = (x**2 for x in range(10))
for square in squares_generator:
print(square) # 輸出: 0, 1, 4, 9, 16, 25, 36, 49, 64, 81
```
### 綜合練習題
讓我們綜合使用不同的 comprehension 來解決一個複雜的問題。假設我們有一個包含學生姓名和成績的列表,我們希望建立一個字典,鍵是學生的姓名,值是他們的成績,並且只包含成績大於 75 的學生。
```python
students = [('Alice', 85), ('Bob', 70), ('Charlie', 90), ('David', 65)]
# 使用字典推導式
passed_students = {name: score for name, score in students if score > 75}
print(passed_students) # 輸出: {'Alice': 85, 'Charlie': 90}
```
## 關鍵內容 List Comprehension vs. Generator Expression
Generator Expression 是個很特別的東西,這邊特別拿來與 List Comprehension 做比較。
### 基本概念
* **List Comprehension (列表推導式)**:
* 用於建立列表的簡潔語法。
* 會立即生成並儲存所有元素
* **Generator Expression (生成器推導式)**:
* 用於建立生成器的簡潔語法。
* 不會立即生成所有元素,而是根據需要逐個生成元素。
### 記憶體使用
* **List Comprehension**:
* 會立即建立並儲存整個列表,這意味著它會佔用與列表大小成正比的記憶體。
* 如果列表非常大,則會消耗大量記憶體,可能導致記憶體不足。
```python
squares_list = [x**2 for x in range(1000000)]
```
在這個範例中,**squares_list** 會立即包含 1,000,000 個平方數,佔用大量記憶體。
* **Generator Expression**:
* 只會在需要時生成每個元素,因此只佔用很少的記憶體。
* 非常適合處理大型數據集或需要逐個處理元素的情況。
```python
squares_generator = (x**2 for x in range(1000000))
```
在這個範例中,**squares_generator** 不會立即生成所有平方數,而是根據需要逐個生成,佔用的記憶體非常少。
### 執行效率
* **List Comprehension**:
* 因為列表已經全部生成,所以對列表進行遍歷或操作會更快。
* 適合需要多次訪問或操作列表元素的情況。
* **Generator Expression**:
* 因為元素是逐個生成的,所以第一次遍歷生成器會比列表慢。
* 適合一次性生成和處理元素的情況,不適合需要多次遍歷的情況。
### 記憶體使用測試
```python
import sys
# 使用列表推導式建立一個包含 1,000,000 個元素的列表
squares_list = [x**2 for x in range(1000000)]
# 列表大小
print(f"列表大小: {sys.getsizeof(squares_list)} bytes")
# 使用生成器推導式建立一個包含 1,000,000 個元素的生成器
squares_generator = (x**2 for x in range(1000000))
# 生成器大小
print(f"生成器大小: {sys.getsizeof(squares_generator)} bytes")
```
輸出結果會顯示列表和生成器在記憶體使用上的巨大差異:

從這裡可以看出,生成器推導式佔用的記憶體非常少,而列表推導式會佔用大量的記憶體。
### 結論
* **列表推導式** 適合在記憶體充裕且需要多次訪問或操作整個數據集的情況下使用。
* **生成器推導式** 適合在處理大型數據集且需要逐個生成和處理元素的情況下使用,特別是當記憶體資源有限時。
## 結語
理解和掌握 Python 的 comprehension 語法可以讓你的程式碼更加簡潔和具可讀性。列表推導式、集合推導式、字典推導式和生成器推導式各有其應用場景,熟練運用這些技巧將大大提升你的 coding 效率。
希望這篇文章對觀眾老爺有幫助!如果有任何問題或建議,歡迎在評論區留言。