器→工具, 编程语言

Python 类型注解(Type Hints)详解

钱魏Way · · 161 次浏览

类型注解的概念

类型注解(Type Hints) 是 Python 3.5+ 引入的特性(通过 PEP 484),允许开发者为变量、函数参数和返回值等标注期望的数据类型。它不会影响代码运行时行为,但可通过静态检查工具(如 mypy)提前发现类型错误,提升代码健壮性和可维护性。

  • 定义:类型注解(Type Hints)是为变量、函数参数、返回值等标注预期类型的一种语法,帮助开发者明确代码意图。
  • 作用:
    • 提升代码可读性和可维护性。
    • 支持静态类型检查工具(如 `mypy`)发现潜在错误。
    • 增强 IDE 的代码提示和自动补全功能。
  • 注意:Python 仍是动态类型语言,类型注解不会影响运行时行为。

基本语法

变量类型注解

使用 `: Type` 标注变量类型:

name: str = "Alice"
age: int = 30
scores: list[float] = [90.5, 85.0]

函数参数与返回值

  • 参数:`参数名: 类型`
  • 返回值:`-> 返回类型`
def add(a: int, b: int) -> int:
    return a + b

容器类型

使用 `typing` 模块中的泛型(Python 3.9+ 可直接用内置容器):

from typing import List, Dict, Tuple

# 列表:元素为整数
numbers: List[int] = [1, 2, 3]
# 字典:键为字符串,值为浮点数
prices: Dict[str, float] = {"apple": 4.5, "banana": 2.0}
# 元组:固定类型和长度
point: Tuple[float, float, str] = (3.5, 4.2, "坐标")

类与对象

类属性与方法返回值标注:

class User:
    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age: int = age  # 实例属性注解

    def get_info(self) -> str:
        return f"{self.name}, {self.age}"

高级类型注解

联合类型(Union)

表示变量可以是多个类型之一:

from typing import Union


def parse_input(input: Union[str, int]) -> None:
    pass

可选类型(Optional)

等同于 `Union[T, None]`,表示值可能为 `None`:

from typing import Optional


def find_user(id: int) -> Optional["User"]:
    # 可能返回 User 对象或 None
    pass

类型别名(Type Alias)

简化复杂类型定义:

from typing import List, Tuple

Coordinates = List[Tuple[float, float]]

def draw(points: Coordinates) -> None:
    pass

泛型(Generics)

自定义泛型类或函数:

from typing import TypeVar, Generic

T = TypeVar('T')


class Box(Generic[T]):
    def __init__(self, item: T) -> None:
        self.item = item

字面量类型(Literal)

限制变量为特定值(Python 3.8+):

from typing import Literal


def set_mode(mode: Literal["read", "write"]) -> None:
    pass

回调函数类型(Callable)

标注函数参数类型:

from typing import Callable


def on_click(callback: Callable[[int, str], None]) -> None:
    pass

协议与结构子类型(Duck Typing)

通过 Protocol 定义接口,无需继承即可匹配类型:

from typing import Protocol

class Flyer(Protocol):
    def fly(self) -> str: ...

class Bird:
    def fly(self) -> str:
        return "Flapping wings"

def takeoff(obj: Flyer) -> None:
    print(obj.fly())

takeoff(Bird())  # 合法,因为 Bird 实现了 fly 方法

泛型(Generics)

泛型是什么?

泛型(Generics) 是一种编程范式,允许你编写可操作多种数据类型的代码,同时保持 类型安全。通过泛型,可以定义 参数化的类型(如 List[T]),其中 T 是一个类型变量,表示实际使用时确定的类型。泛型的核心目标是:

  • 代码复用:避免为不同类型重复编写相似逻辑。
  • 类型约束:明确操作的数据类型,减少运行时错误。
  • 静态检查支持:配合工具(如mypy)提前发现类型不匹配问题。

Python 中的泛型实现

Python 通过 typing 模块(Python 3.5+)和内置语法(Python 3.12+)支持泛型。

基本语法

定义泛型类型变量:使用 TypeVar。

from typing import TypeVar, Generic

T = TypeVar('T')  # 定义泛型类型变量 T

泛型类:继承 Generic[T]。

class Box(Generic[T]):
    def __init__(self, item: T) -> None:
        self.item = item

    def get_item(self) -> T:
        return self.item

# 使用
int_box = Box(10)          # Box[int]
str_box = Box("hello")     # Box[str]

泛型函数:直接使用类型变量。

from typing import TypeVar

T = TypeVar('T')

def first_element(items: list[T]) -> T:
    return items[0]

print(first_element([1, 2, 3]))        # int
print(first_element(["a", "b", "c"])) # str

Python 3.12+ 的新语法

Python 3.12 引入更简洁的泛型语法(PEP 695),无需显式使用 TypeVar 和 Generic:

class Box[T]:
    def __init__(self, item: T) -> None:
        self.item = item

    def get_item(self) -> T:
        return self.item

def first_element[T](items: list[T]) -> T:
    return items[0]

泛型的核心应用场景

容器类(如列表、字典)

定义可容纳任意类型但内部类型一致的容器:

from typing import Generic, TypeVar, Iterable

T = TypeVar('T')

class LinkedList(Generic[T]):
    def __init__(self, items: Iterable[T]) -> None:
        self.items = list(items)

    def append(self, item: T) -> None:
        self.items.append(item)

# 使用
int_list = LinkedList([1, 2, 3])        # LinkedList[int]
str_list = LinkedList(["a", "b", "c"])  # LinkedList[str]

通用算法

编写与类型无关的算法逻辑:

from typing import TypeVar, Sequence

T = TypeVar('T')

def max_element(seq: Sequence[T]) -> T:
    return max(seq)  # 假设元素可比较

print(max_element([3, 1, 4]))     # 4
print(max_element(["z", "a", "b"]))  # "z"

API 设计

设计可处理多种类型的接口:

from typing import TypeVar, Callable

Input = TypeVar('Input')
Output = TypeVar('Output')

def transform_data(
    data: Input, 
    converter: Callable[[Input], Output]
) -> Output:
    return converter(data)

# 使用
result_str = transform_data(100, lambda x: str(x))  # Output: str
result_int = transform_data("123", int)             # Output: int

高级泛型特性

类型边界(Type Bounds)

限制类型变量的取值范围:

from typing import TypeVar, Number

N = TypeVar('N', bound=Number)  # 必须是 Number 的子类(如 int, float)

def add(a: N, b: N) -> N:
    return a + b

add(1, 2)      # 合法
add(3.14, 2.5) # 合法
add("a", "b")  # 类型检查报错

协变(Covariant)与逆变(Contravariant)

控制泛型类型的继承关系:

  • 协变(covariant=True):子类泛型可替代父类(如list[Child] 可视为 list[Parent])。
  • 逆变(contravariant=True):父类泛型可替代子类(较少使用)。
from typing import TypeVar, Generic

class Animal: ...
class Dog(Animal): ...

T_co = TypeVar('T_co', covariant=True)

class Cage(Generic[T_co]):
    def get_animal(self) -> T_co: ...

def get_animal_from_cage(cage: Cage[Animal]) -> Animal:
    return cage.get_animal()

dog_cage: Cage[Dog] = Cage()
get_animal_from_cage(dog_cage)  # 合法(协变允许 Cage[Dog] 作为 Cage[Animal] 使用)

注意事项

  • 运行时类型擦除:泛型类型信息在运行时不可见(仅用于静态检查)。
  • 避免过度泛型化:仅在需要类型安全时使用,否则会增加代码复杂度。
  • 动态类型兼容:Python 的动态特性可能绕过泛型约束,需配合工具链检查。
  • 性能影响:泛型本身不影响运行时性能,但复杂类型检查可能增加静态分析时间。

类型检查工具

mypy

  • 安装:`pip install mypy`
  • 使用:`mypy your_script.py`
  • 配置:在 `pyproject.toml` 中添加:
[tool.mypy]
ignore_missing_imports = true
strict = true

IDE 支持

  • VS Code:安装 `Python` 扩展和 `Pylance`。
  • PyCharm:内置类型检查,支持自动提示。

最佳实践

  • 逐步引入:在关键模块(如公共接口、复杂逻辑)优先添加类型注解。
  • 避免过度使用Any:尽量明确类型,否则会削弱检查效果。
  • 兼容性处理
    • 对旧代码使用# type: ignore 临时忽略错误。
    • 用typing 模块兼容不同 Python 版本。
  • 文档生成:结合sphinx 或 pdoc 生成类型化文档。

常见问题与解决方案

循环引用

使用字符串形式的类型注解:

class Node:
    def __init__(self, parent: "Node") -> None:
        self.parent = parent

动态类型处理

类型断言

value: Any = get_data()
str_value: str = value  # 不安全的转换
safe_str = cast(str, value)  # 明确告知类型检查器

类型保护

def process(data: Union[int, str]) -> None:
    if isinstance(data, int):
        print(data + 1)
    else:
        print(data.upper())

One Reply to “Python 类型注解(Type Hints)详解”

  1. 期待梳理一下pydantic,这个库类似于python api领域的数据模式定义,在fastapi中应用广泛

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注