• 微信:WANCOME
  • 扫码加微信,提供专业咨询
  • 服务热线
  • 13215191218
    13027920428

  • 微信扫码访问本页
desc-2
环企首页

Python typing模块详解

typing 模块是 Python 中用于类型提示(Type Hints)的标准库,它允许你在代码中标注变量、函数参数和返回值的类型。这极大地提升了代码的可读性、可维护性,并为 IDE 和静态检查工具提供了支持。

1. 为什么需要类型提示?

没有类型提示(容易出错)

def add(a, b):
    return a + b

result = add("hello", "world")  # 返回 "helloworld",可能不是期望的行为

有类型提示(更清晰)

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

# IDE 会提示你传递字符串可能有问题
result = add(5, 3)   # 正确使用

2. 基础类型

from typing import List, Dict, Tuple, Set

# 基础类型
name: str = "Alice"
age: int = 25
price: float = 19.99
is_active: bool = True

# 集合类型
names: List[str] = ["Alice", "Bob"]           # 字符串列表
scores: Dict[str, int] = {"math": 95}         # 字符串→整数映射
point: Tuple[int, int] = (10, 20)             # 两个整数的元组
tags: Set[str] = {"python", "coding"}         # 字符串集合

3. 函数注解

def greet(name: str, age: int = 18) -> str:
    """返回问候语"""
    return f"{name} 今年 {age} 岁"

def process_data(data: List[int]) -> Dict[str, float]:
    """处理数据并返回结果"""
    return {"average": sum(data) / len(data)}

# 无返回值
def log_message(msg: str) -> None:
    print(f"[LOG] {msg}")

4. 可选类型和联合类型

Optional:可能为 None

from typing import Optional

def find_user(user_id: int) -> Optional[str]:
    """返回用户名,如果不存在则返回 None"""
    if user_id == 1:
        return "Alice"
    return None

# Python 3.10+ 可以写成 str | None
def get_config(key: str) -> str | None:
    return os.getenv(key)

Union:多种可能的类型

from typing import Union

# Python 3.10+ 推荐使用 | 语法
def process(value: Union[int, str]) -> str:  # 旧语法
    return str(value)

# 新语法(Python 3.10+)
def process(value: int | str) -> str:
    return str(value)

# 多种类型
def convert(data: int | float | str) -> float:
    return float(data)

5. 高级类型

Any:任意类型(绕过类型检查)

from typing import Any

def flexible_func(data: Any) -> Any:
    """可以接受和返回任何类型"""
    return data

# 不推荐过度使用,会失去类型检查的好处

TypeVar:泛型

from typing import TypeVar, List

T = TypeVar('T')  # 类型变量

def first_element(items: List[T]) -> T:
    """返回列表的第一个元素,类型与列表元素一致"""
    return items[0]

# 使用时自动推断类型
result1 = first_element([1, 2, 3])     # result1 被推断为 int
result2 = first_element(["a", "b"])    # result2 被推断为 str

Callable:函数类型

from typing import Callable

def apply_operation(x: int, y: int, operation: Callable[[int, int], int]) -> int:
    """应用一个二元运算函数"""
    return operation(x, y)

# 使用
result = apply_operation(5, 3, lambda a, b: a + b)  # 8
result = apply_operation(5, 3, lambda a, b: a * b)  # 15

6. 特殊类型

Literal:字面量类型(Python 3.8+)

from typing import Literal

def set_mode(mode: Literal['read', 'write', 'append']) -> None:
    """mode 只能是 'read'、'write' 或 'append'"""
    print(f"Mode set to {mode}")

set_mode('read')     # 正确
# set_mode('delete')  # 类型检查器会报错

TypedDict:字典的结构定义

from typing import TypedDict

class User(TypedDict):
    name: str
    age: int
    email: str

# 使用时,IDE 会提供字段提示
user: User = {
    "name": "Alice",
    "age": 25,
    "email": "alice@example.com"
}

print(user["name"])  # IDE 知道这是一个字符串

Protocol:结构性子类型(Python 3.8+,又名静态鸭子类型)

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> None: ...

def render(obj: Drawable) -> None:
    obj.draw()

class Circle:
    def draw(self) -> None:
        print("绘制圆形")

class Square:
    def draw(self) -> None:
        print("绘制正方形")

render(Circle())  # 有效,因为 Circle 实现了 draw 方法
render(Square())  # 有效

7. 新旧语法对比

功能 Python < 3.9 Python 3.9+ Python 3.10+
列表 List[int] list[int] list[int]
字典 Dict[str, int] dict[str, int] dict[str, int]
元组 Tuple[int, str] tuple[int, str] tuple[int, str]
可选 Optional[str] Optional[str] str | None
联合 Union[int, str] Union[int, str] int | str

建议:如果你的 Python 版本 >= 3.9,优先使用内置类型(listdict)而非 typing 中的大写版本;如果 >= 3.10,优先使用 | 语法而非 UnionOptional

8. 实际应用示例

数据模型

from typing import List, Dict, Optional
from dataclasses import dataclass

@dataclass
class Address:
    street: str
    city: str
    zipcode: str

@dataclass
class User:
    id: int
    name: str
    email: str
    address: Optional[Address] = None
    tags: List[str] = None

API 客户端

import requests
from typing import Dict, Any, Optional

class APIClient:
    def __init__(self, base_url: str, api_key: str) -> None:
        self.base_url = base_url
        self.api_key = api_key
    
    def get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        response = requests.get(
            f"{self.base_url}/{endpoint}",
            params=params,
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        response.raise_for_status()
        return response.json()
    
    def post(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]:
        response = requests.post(
            f"{self.base_url}/{endpoint}",
            json=data,
            headers={"Authorization": f"Bearer {self.api_key}"}
        )
        return response.json()

函数重载(通过类型提示)

from typing import overload, Union

@overload
def process(data: int) -> int:
    ...

@overload
def process(data: str) -> str:
    ...

def process(data: Union[int, str]) -> Union[int, str]:
    if isinstance(data, int):
        return data * 2
    else:
        return data.upper()

9. 类型检查工具

类型提示本身不会在运行时强制检查,需要借助工具:

工具 说明
mypy 最流行的静态类型检查器
pylint 代码检查工具,支持类型提示
PyCharm IDE 内置类型检查
VS Code Pyright / Pylance 扩展

使用 mypy

# 安装
pip install mypy

# 运行检查
mypy your_script.py

# 忽略缺失的库类型
mypy --ignore-missing-imports your_script.py

10. 类型别名

from typing import List, Dict

# 定义类型别名
UserId = int
UserData = Dict[str, str]
UserList = List[UserId]

def get_users() -> UserList:
    return [1, 2, 3]

def process_user(user_id: UserId, data: UserData) -> None:
    print(f"Processing user {user_id}: {data}")

11. 运行时访问类型信息

from typing import get_type_hints

def greet(name: str, age: int = 18) -> str:
    return f"{name} is {age} years old"

# 获取函数的类型提示
hints = get_type_hints(greet)
print(hints)  # {'name': , 'age': , 'return': }

12. 总结

要点 说明
核心价值 提高代码可读性、支持 IDE 智能提示、帮助提前发现错误
运行时 类型提示不会影响运行效率,只是辅助工具
静态检查 配合 mypy、Pyright 等工具实现真正的类型检查
最佳实践 公共 API 必须写类型提示;内部函数也建议写
版本迁移 Python >= 3.9 使用内置容器类型;>= 3.10 使用 | 语法

类型提示是现代 Python 开发的必备技能,它能让你的代码更加健壮、可维护,特别是在大型项目或团队协作中。