Python Union 型完全指南|舊式與新式語法及實用範例詳解

目次

1. 前言

什麼是 Python 的型別提示?

Python 是一種動態型別語言,即使沒有明確指定變數的型別,也能正常執行程式。不過,在大型專案或團隊開發中,為了提高程式碼的可讀性與維護性,明確的型別資訊變得非常重要。為了解決這個問題,Python 引入了「型別提示」。

型別提示是用來明確指定變數、函式參數與回傳值所預期的資料型別。這樣一來,不僅讓其他開發者能更容易理解變數的用途,未來自己回來看程式碼時也更容易上手。此外,透過靜態分析工具,可以在執行前就偵測出型別錯誤。

Union 型的重要性

Union 型是一種允許多種不同資料型別的型別提示。例如,當一個函式可以接受整數或字串作為輸入時,使用 Union 型可以清楚表達這種彈性。

來看看下面的範例:

from typing import Union

def process_data(data: Union[int, str]) -> None:
    print(data)

這個函式可以接受整數或字串,並直接將其輸出。藉由型別提示,其他開發者可以清楚了解這個函式接受哪些型別的輸入,也更放心地使用。

Union 型的應用場景

  1. 當需要設計能處理多種資料格式的函式時。
  2. 當 API 回傳的資料可能有多種型別時。
  3. 在設計支援彈性輸入格式的函式或工具庫時。

下一章將進一步介紹 Union 型的基本使用方式與語法細節。


2. 什麼是 Union 型?

Union 型的定義與基本概念

Union 型是 Python 中用來指定一個變數、參數或回傳值可以是多種資料型別之一的方式。透過 Union 型,即使一個值可能有不同型別,也能同時確保程式的彈性與型別安全。

Union 型主要有以下幾個用途:

  • 定義能接受不同資料格式的函式。
  • 開發處理多種型別的工具或函式庫。
  • 加強靜態型別檢查工具的驗證功能。

Union 型的實際範例

例如,我們可以定義一個同時接受字串與數值的函式:

from typing import Union

def add_values(value1: Union[int, float], value2: Union[int, float]) -> Union[int, float]:
    return value1 + value2

在這個範例中,add_values 函式能夠接受整數與浮點數,並且回傳同樣的型別。透過 Union 型,可以簡潔地處理多種型別的資料。

Union 型的特點

  1. 彈性高
    允許多種型別輸入,使函式更易於應用在不同場景。
  2. 型別檢查加強
    搭配靜態分析工具(如 mypy)可以在開發階段即早發現型別錯誤。
  3. 可讀性提升
    明確的型別提示讓程式碼對開發者更直觀易懂。

Union 型的應用實例

以下是可接受字串或字串列表的函式範例:

from typing import Union, List

def format_data(data: Union[str, List[str]]) -> List[str]:
    if isinstance(data, list):
        return data
    else:
        return [data]

這個函式可以同時處理單一字串與字串清單,並統一轉換為列表形式回傳。這樣就能在確保型別一致性的同時,保有輸入的彈性。

銜接下一章節

接下來的章節將會介紹 Python 3.10 之前使用 Union 型時所採用的傳統語法,並說明與新版語法之間的差異。

RUNTEQ(ランテック)|超実戦型エンジニア育成スクール

3. 傳統的 Union 型指定方式

Python 3.10 之前的 Union 型寫法

在 Python 3.10 以前的版本中,若要指定 Union 型,需要從 typing 模組中匯入 Union 並使用它。這種方式目前仍可使用,但從 Python 3.10 開始,加入了更簡潔的新語法。

基本用法

以下範例示範了 Python 3.10 以前使用 Union 型的方式:

from typing import Union

def process_input(data: Union[int, float]) -> float:
    return float(data)

在這個範例中,參數 data 可以是整數或浮點數,而回傳值會是浮點數。透過 Union[int, float],可以讓函式接受多種型別,提高靈活性。

多種 Union 型的應用方式

指定多個參數的型別

以下範例顯示函式接受多種型別參數的情況:

from typing import Union

def display_value(value: Union[int, str]) -> None:
    print(f"Value: {value}")

彈性的回傳值型別

以下範例示範函式的回傳值可能是多種型別之一:

from typing import Union

def process_data(data: str) -> Union[int, None]:
    if data.isdigit():
        return int(data)
    return None

程式碼可讀性與挑戰

雖然傳統的 Union 很強大,但也有以下幾點常見問題:

  • 容易造成程式碼冗長。
  • 當型別列表過長時,可讀性會下降。
  • 書寫錯誤導致型別錯誤的風險較高。

範例:複雜的型別指定

from typing import Union, List, Tuple

def process_items(items: Union[List[int], Tuple[int, ...]]) -> None:
    for item in items:
        print(item)

這段程式碼可以接受整數列表或整數元組作為輸入,不過過多的 Union 使用讓程式碼變得較長且複雜。

銜接下一章節

為了解決上述問題,Python 3.10 引入了更簡潔的 Union 型寫法。下一章將會詳細介紹新版語法的寫法與優點。


4. 新的 Union 型寫法(支援 PEP 604)

從 Python 3.10 開始的新語法是什麼?

自 Python 3.10 起,引入了更簡單易讀的 Union 型寫法。這項改變來自 PEP 604 提案,讓程式碼更容易撰寫與維護,提升可讀性與效率。

新語法中,可以使用管線符號 | 來表示多種型別的組合,取代原本冗長的 Union[]

新語法的基本範例

以下程式碼使用新語法定義 Union 型別:

def process_input(data: int | float) -> float:
    return float(data)

這裡的 process_input 函式接受整數或浮點數,並回傳一個浮點數。這與 Union[int, float] 的意思相同,但語法更加簡潔清楚。

舊語法與新語法的比較

Python 3.10 以前(舊語法)Python 3.10 以後(新語法)
Union[int, str]int | str
Union[List[int], Tuple[int, ...]]List[int] | Tuple[int, ...]
Optional[str](包含 None)str | None

新語法的優點

  1. 簡化程式碼
  • 新語法更短、更直觀,減少閱讀與撰寫負擔。
  1. 提升可讀性
  • 使用 | 符號表示「或」,更容易理解其邏輯含義。
  1. 與其他複雜型別搭配更靈活
  • 像是巢狀型別、列表、元組等也能輕鬆組合。

使用新語法的範例

接受多種資料型別的函式

def display_value(value: int | str) -> None:
    print(f"Value: {value}")

函式的回傳值可以是多型別

def process_data(data: str) -> int | None:
    if data.isdigit():
        return int(data)
    return None

複雜型別指定的例子

def combine_data(data: list[int] | tuple[int, ...]) -> list[int]:
    return list(data)

新語法的注意事項與相容性

  1. 無法在 Python 3.10 以前使用
  • 此語法僅適用於 Python 3.10 以上版本,舊環境需使用 Union
  1. 與靜態型別工具的相容性
  • mypy 等靜態分析工具已支援新語法,但請確認工具版本是否相容。

銜接下一章節

接下來我們會透過實際的應用範例,比較新舊兩種 Union 型的語法,並探討如何在開發中有效活用它們。

5. 實戰!Union 型的應用範例

資料分析工具中的使用範例

Union 型常應用於資料分析與統計處理中。以下是一個接受整數或整數列表的輸入並進行處理的函式範例:

def calculate_average(data: int | list[int]) -> float:
    if isinstance(data, int):
        return float(data)
    elif isinstance(data, list):
        return sum(data) / len(data)
    else:
        raise TypeError("Unsupported data type")

重點說明

  1. 確保彈性
  • 此函式能同時處理單一整數或整數列表,減少輸入限制。
  1. 錯誤處理
  • 若輸入非預期型別,將主動拋出錯誤訊息,有助於快速除錯。

處理 API 回應資料的範例

API 回傳資料的格式可能不一致,Union 型有助於處理這種情況:

from typing import Any

def parse_response(response: dict[str, Any] | list[dict[str, Any]]) -> list[dict[str, Any]]:
    if isinstance(response, dict):
        return [response]  # 單一物件轉為列表
    elif isinstance(response, list):
        return response  # 直接回傳
    else:
        raise ValueError("Invalid response format")

重點說明

  1. 支援多種輸入格式
  • 不論回應是單一物件或物件列表,都能統一處理。
  1. 統一輸出格式
  • 統一回傳為列表,讓後續邏輯更簡潔一致。

使用者輸入表單的驗證範例

由於使用者輸入的資料可能格式多樣,使用 Union 型可以靈活驗證不同型別:

def validate_input(data: str | int | float) -> str:
    if isinstance(data, str):
        if not data.strip():
            raise ValueError("String cannot be empty")
        return data
    elif isinstance(data, (int, float)):
        if data < 0:
            raise ValueError("Number cannot be negative")
        return str(data)
    else:
        raise TypeError("Unsupported input type")

設定管理的多型別處理範例

在讀取設定檔時,資料格式可能是字串或字典,以下範例展示如何處理:

def load_config(config: str | dict[str, str]) -> dict[str, str]:
    import json
    if isinstance(config, str):
        # 若為檔案路徑,讀取 JSON
        with open(config, 'r') as file:
            return json.load(file)
    elif isinstance(config, dict):
        # 已是字典則直接使用
        return config
    else:
        raise TypeError("Invalid configuration format")

總結

這些實際應用範例顯示,Union 型能有效提高程式碼的彈性與安全性。無論是資料分析、API 處理或輸入驗證,Union 型皆可廣泛應用。


6. 注意事項與最佳實踐

型別別名的使用方式

雖然 Union 型提供彈性,但當型別變得過於複雜時,可能會降低可讀性。這時候可透過「型別別名」來改善:

型別別名範例

DataType = int | float | str

def process_data(data: DataType) -> str:
    return str(data)

此範例中,DataType 是自定義的型別別名,統一表示多種型別。能讓程式碼更清楚,也便於多次重複使用。

善用靜態分析工具

搭配靜態型別檢查工具,可大幅提升程式的可靠性與維護性。

mypy 的基本用法

pip install mypy
mypy script.py

範例程式碼:

from typing import Union

def calculate_total(price: int | float, quantity: int) -> float:
    return price * quantity

使用 mypy 檢查後,可提早發現型別不符的錯誤。

過度使用型別指定的風險

雖然 Union 型提供彈性,但若過度使用或寫法過於複雜,反而會使程式難以理解與維護。

反面範例

def complex_function(data: int | float | str | list[str] | dict[str, int]) -> str:
    # 型別過於複雜,不易理解
    return str(data)

改善後的寫法

SimpleType = int | float | str
ComplexType = list[str] | dict[str, int]

def process_simple(data: SimpleType) -> str:
    return str(data)

def process_complex(data: ComplexType) -> str:
    return str(data)

型別安全與預設值的搭配

當函式參數有預設值時,建議使用 | NoneOptional 來明確表示可為空值的狀況。

處理預設值的函式範例

def fetch_data(key: str, default: str | None = None) -> str:
    data = {"name": "Python", "version": "3.10"}
    return data.get(key, default) or "Unknown"

總結

為了更安全有效地使用 Union 型,請留意以下幾點:

  1. 使用型別別名提升可讀性與重用性。
  2. 搭配靜態分析工具預先偵測型別錯誤。
  3. 避免過度複雜的型別組合,保持程式簡潔。
  4. 妥善運用預設值與可選型別強化錯誤處理。

7. 常見問題(FAQ)

Q1. Union 型與 Any 型有何不同?

Union 型與 Any 型都能處理多種型別,但它們的使用目的與方式有明顯差異:

項目Union 型Any 型
型別指定明確指定允許的型別(例如:int | str接受任何型別(例如:Any
型別檢查限定型別,其他型別會報錯不進行型別檢查
適用場景有特定型別組合的情況需要完全自由型別的函式或變數

程式碼範例

Union 型:

def display_value(value: int | str) -> None:
    print(value)

Any 型:

from typing import Any

def display_value(value: Any) -> None:
    print(value)

Q2. Python 3.10 以前與以後的 Union 型是否相容?

是的,兩種寫法是相容的。Python 3.10 引入了新語法,但舊的 Union 寫法仍然可使用。

範例:相容的寫法

from typing import Union

# 舊語法
def old_union(data: Union[int, str]) -> None:
    print(data)

# 新語法
def new_union(data: int | str) -> None:
    print(data)

Q3. 型別提示會影響執行效能嗎?

不會。型別提示僅作為開發輔助資訊,在執行階段並不會影響程式的效能。它主要用於靜態分析工具與 IDE 的補全提示。

但若搭配像 mypy 這類工具,則有以下好處:

  1. 在撰寫階段就能提早發現錯誤。
  2. 強化 IDE 的智慧提示與補全功能,提高開發效率。

Q4. Optional 型與 Union 型有何不同?

Optional 型是 Union 型的一種特例,用來表示某個值可以是特定型別或 None

Union 型範例:

def process_data(data: int | None) -> str:
    return str(data) if data is not None else "No data"

Optional 型範例:

from typing import Optional

def process_data(data: Optional[int]) -> str:
    return str(data) if data is not None else "No data"

Q5. 靜態分析工具是必要的嗎?

雖然不是強制使用,但非常建議搭配靜態分析工具,能顯著提升程式碼品質與維護效率。

原因如下:

  1. 幫助發現潛在錯誤。
  2. 提升除錯與開發速度。
  3. 在團隊開發中維持一致性。

推薦工具

  • mypy: 適合嚴格型別檢查。
  • Pyright: 提供快速且即時的型別分析。

mypy 使用範例

pip install mypy
mypy script.py

總結

本章 FAQ 針對 Union 型常見問題進行說明,包括它與 Any、Optional 的差異,以及靜態工具的實用性。

  • Union 型與 Any 用途不同,應根據需求選用。
  • 新舊語法相容,開發階段可自由切換。
  • 靜態分析工具有助於提升品質與安全性。

8. 推薦工具與函式庫

mypy:靜態型別檢查工具

什麼是 mypy?
mypy 是一款支援 Python 型別提示的靜態分析工具,能夠驗證 Union 型等型別是否正確。

功能特色

  • 在執行前發現型別錯誤。
  • 協助大型專案維持高品質程式碼。
  • 完全支援 Python 型別提示語法。

安裝方式

pip install mypy

使用範例

from typing import Union

def process_input(data: Union[int, str]) -> str:
    return str(data)

process_input(100)  # OK
process_input("hello")  # OK
process_input(10.5)  # 錯誤:型別不符

執行型別檢查

mypy script.py

Pyright:快速型別檢查工具

什麼是 Pyright?
Pyright 是由 Microsoft 開發的 Python 型別檢查工具,特別適合與 VSCode 結合使用,可即時分析程式。

功能特色

  • 高效且快速。
  • 與 VSCode 整合流暢。
  • 支援自動型別推論。

安裝方式

npm install -g pyright

使用範例

def validate_input(data: int | str) -> str:
    if isinstance(data, int):
        return str(data)
    elif isinstance(data, str):
        return data
    return "Invalid input"  # 檢查工具會偵測此問題

Pydantic:資料驗證與型別檢查

什麼是 Pydantic?
Pydantic 是一款可根據型別提示進行資料驗證與序列化的函式庫,非常適合搭配 Union 型處理複雜資料結構。

功能特色

  • 強大支援 JSON 與 API 驗證。
  • 支援自動型別轉換。
  • 能夠定義安全又清晰的資料模型。

安裝方式

pip install pydantic

使用範例

from pydantic import BaseModel
from typing import Union

class Item(BaseModel):
    name: str
    value: Union[int, float]

item = Item(name="example", value=42)
print(item)

IDE 支援:PyCharm 與 VSCode

現代 IDE 提供完善的型別提示與檢查功能,能提升 Union 型開發效率。

推薦 IDE

  • PyCharm: 強大的型別提示與警告功能,適合專業開發者。
  • VSCode: 搭配 Python 與 Pyright 外掛,提供輕量且快速的開發體驗。

總結

透過這些工具與函式庫,可以更有效地利用 Union 型,提升程式安全性與開發效率。

推薦工具整理:

  • mypy: 嚴格靜態型別檢查。
  • Pyright: 即時、快速型別分析。
  • Pydantic: 適合資料模型與驗證處理。
  • PyCharm / VSCode: 提供強大 IDE 支援。

9. 總結

Union 型的實用性與進化重點

本文從基礎到進階,完整介紹了 Python 中 Union 型的定義、應用與最佳實踐。

以下是本文重點整理:

  1. 基本概念:
  • Union 型可容納多種資料型別,提高靈活性與型別安全。
  1. 新舊語法差異:
  • Python 3.10 以前使用 Union[X, Y],以後可使用簡潔的 X | Y
  1. 應用場景:
  • 資料分析、API 回應處理、使用者輸入驗證等。
  1. 實踐建議:
  • 配合靜態工具檢查型別。
  • 善用型別別名提升可讀性。

建議使用 Python 3.10 以上版本開發

新語法不僅簡潔,還能提升維護效率與可讀性。以下是新語法範例:

def process_input(data: int | str) -> str:
    return str(data)

給讀者的下一步建議

  1. 實作練習
  • 嘗試在專案中實際使用 Union 型。
  1. 進一步學習
  1. 套用於現有專案
  • 逐步導入 Union 型,提升程式碼品質與可維護性。

結語

Union 型是強化 Python 靈活性與安全性的強大工具,尤其在 Python 3.10 新語法推出後,其實用性更進一步提升。

希望透過本指南,您能更自信地活用 Union 型於各種開發情境中!

繼續努力,讓你的 Python 技能更上一層樓!

年収訴求