---
# System prepended metadata

title: 一次了解 Python Comprehension 的用法
tags: [python]

---

# 一次了解 Python Comprehension 的用法

![chris-ried-ieic5Tq8YMk-unsplash](https://hackmd.io/_uploads/Sy0W6-KDA.jpg)
> *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")
```

輸出結果會顯示列表和生成器在記憶體使用上的巨大差異：

![image](https://hackmd.io/_uploads/SyUvOGYD0.png)

從這裡可以看出，生成器推導式佔用的記憶體非常少，而列表推導式會佔用大量的記憶體。

### 結論
* **列表推導式** 適合在記憶體充裕且需要多次訪問或操作整個數據集的情況下使用。
* **生成器推導式** 適合在處理大型數據集且需要逐個生成和處理元素的情況下使用，特別是當記憶體資源有限時。

## 結語
理解和掌握 Python 的 comprehension 語法可以讓你的程式碼更加簡潔和具可讀性。列表推導式、集合推導式、字典推導式和生成器推導式各有其應用場景，熟練運用這些技巧將大大提升你的 coding 效率。

希望這篇文章對觀眾老爺有幫助！如果有任何問題或建議，歡迎在評論區留言。