Skip to content

02-类型进阶应用

Python 版本要求:3.11+ 本章使用 Python 3.11+ 现代语法,主要改进包括:

  • 使用内置泛型(list[int] 而非 List[int]
  • 使用联合操作符(int | str 而非 Union[int, str]
  • 使用 Self 类型而非字符串注解
  • 无需从 typing 导入基础容器类型

深入掌握 Python 类型系统的进阶特性。


概念铺垫

Python 类型系统的进阶能力包括:泛型编程(TypeVar/Generic)、结构化子类型(Protocol)、精确字典类型(TypedDict)、运行时类型检查(get_type_hints)和类型收窄(TypeGuard)。这些特性帮助你在不丢失类型安全的前提下编写通用、可复用的代码。


L1 理解层:会用

1. 泛型深入理解

1.1 问题引入

场景: 你想写一个通用的栈类,能存储任意类型的元素。

python
# 每种类型都要写一个类?太麻烦了!
class IntStack:
    def push(self, item: int) -> None: ...
    def pop(self) -> int: ...

class StrStack:
    def push(self, item: str) -> None: ...
    def pop(self) -> str: ...

# 能不能用一个类处理所有类型?

问题: 如何写一个类,既能处理整数,也能处理字符串?


1.2 概念解释

泛型(Generic): 定义时不指定具体类型,使用时再确定。

┌─────────────────────────────────────────────────────┐
│          泛型语法结构                                │
├─────────────────────────────────────────────────────┤
│                                                     │
│  泛型函数:                                          │
│  ───────────────────────────────────────           │
│  def func(items: list[T]) -> T:                    │
│      ↑            ↑        ↑                       │
│      函数名      参数类型   返回类型                 │
│                                                     │
│  泛型类:                                            │
│  ───────────────────────────────────────           │
│  class Box(Generic[T]):                            │
│              ↑         ↑                            │
│           泛型基类   类型参数                        │
│                                                     │
│  类型变量定义:                                      │
│  ───────────────────────────────────────           │
│  T = TypeVar('T')        → 无约束泛型              │
│  N = TypeVar('N', int, float)  → 约束泛型          │
│                                                     │
│  使用示例 → 解释:                                   │
│  Stack[int]    → T 替换为 int,整数栈               │
│  Stack[str]    → T 替换为 str,字符串栈             │
│                                                     │
└─────────────────────────────────────────────────────┘

TypeVar 关键理解点:

┌─────────────────────────────────────────────────────────────┐
│          TypeVar 使用要点                                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. TypeVar 创建类型变量(占位符)                            │
│  ─────────────────────────────────────────────              │
│  • 类似数学中的 x、y 未知数,用具体值替换后才确定            │
│  • T 本身不是类型,T 被替换为 int/str 后才是具体类型         │
│  • 替换发生在静态分析时,不是运行时                          │
│                                                             │
│  2. 'T' 和 T 的含义                                          │
│  ─────────────────────────────────────────────              │
│  T = TypeVar('T')                                           │
│  ↑      ↑                                                   │
│  变量名  字符串名称                                          │
│                                                             │
│  • 'T' 是字符串:类型检查器的名称标识                        │
│  • T 是变量:代码中引用这个类型变量                          │
│  • 两者保持一致便于理解和调试                                │
│                                                             │
│  3. 类型变量替换时机                                          │
│  ─────────────────────────────────────────────              │
│  定义时:def first(items: list[T]) → T   # T 未替换         │
│  使用时:first([1, 2, 3])               # T → int           │
│  推断者:类型检查器(静态分析),不是运行时                   │
│                                                             │
│  4. 常见混淆澄清                                              │
│  ─────────────────────────────────────────────              │
│  ❌ T 是特殊类型     → ✅ T 是占位符                         │
│  ❌ TypeVar 创建类型 → ✅ TypeVar 声明类型变量名             │
│  ❌ 运行时 T 变具体  → ✅ 替换在静态分析时完成               │
│                                                             │
│  5. 与函数参数类比                                            │
│  ─────────────────────────────────────────────              │
│  函数:def f(x): ...          x 是值变量                    │
│  类型:def f(items: list[T]): ...  T 是类型变量             │
│                                                             │
│  • TypeVar('T')  → 声明"类型位置暂用 T 表示"                │
│  • list[T]       → "某个类型的列表,类型待定"               │
│  • list[int]     → T 替换为 int,现在是"整数列表"           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.3 最简示例

python
from typing import TypeVar

T = TypeVar('T')

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

numbers = [1, 2, 3]
first_number = first(numbers)  # 类型是 int

strings = ["a", "b", "c"]
first_string = first(strings)  # 类型是 str

关键代码解释

代码含义为什么这样写
TypeVar('T')定义类型变量 TT 是占位符,使用时替换为具体类型
list[T]参数是 T 类型元素的列表不限制具体类型,任意类型都可以
-> T返回值类型为 T保证返回类型与元素类型一致(类型保持)
first(numbers)T 替换为 int根据参数类型自动推断
first(strings)T 替换为 str根据参数类型自动推断

1.4 详细说明

泛型函数:

python
from typing import TypeVar

T = TypeVar('T')

def reverse(items: list[T]) -> list[T]:
    """反转列表,保持类型"""
    return items[::-1]

def get_middle(items: list[T]) -> T:
    """获取中间元素"""
    return items[len(items) // 2]

# 使用
nums = reverse([1, 2, 3])      # list[int]
chars = reverse(["a", "b"])    # list[str]

mid_num = get_middle([1, 2, 3])      # int: 2
mid_char = get_middle(["a", "b", "c"])  # str: "b"

泛型类:

泛型函数用 TypeVar 声明类型变量,泛型类还需要 Generic 基类。

┌─────────────────────────────────────────────────────────────┐
│          泛型类关键概念                                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. Generic 是什么?                                         │
│  ─────────────────────────────────────────────              │
│  • Generic 是 typing 模块的基类                              │
│  • 用于标记"这个类是泛型类"                                  │
│  • Generic[T] 表示"这个类有一个类型参数 T"                   │
│                                                             │
│  2. 为什么要继承 Generic[T]?                                 │
│  ─────────────────────────────────────────────              │
│  • 不继承:类型检查器不知道 Box 是泛型                       │
│  • 继承后:Box[int]、Box[str] 才是有效的泛型类型              │
│  • Generic[T] 是"声明"机制,不是"继承"行为                   │
│                                                             │
│  3. Generic 和 TypeVar 的关系                                │
│  ─────────────────────────────────────────────              │
│  T = TypeVar('T')        # 先声明类型变量 T                  │
│  class Box(Generic[T]):  # 再用 T 作为类的类型参数           │
│                                                             │
│  • TypeVar:创建类型变量(占位符)                           │
│  • Generic:把类型变量绑定到类                              │
│  • 两者配合:类才能支持泛型                                  │
│                                                             │
│  4. 泛型类的工作流程                                          │
│  ─────────────────────────────────────────────              │
│  定义:class Box(Generic[T]):  # T 是占位符                 │
│  使用:Box[int]                # T 替换为 int               │
│  实例:box = Box(42)           # 创建存储 int 的盒子        │
│                                                             │
│  5. 对比:普通类 vs 泛型类                                    │
│  ─────────────────────────────────────────────              │
│  普通类:                                                    │
│  class IntBox:                                              │
│      def __init__(self, item: int): ...                     │
│      def get(self) -> int: ...                              │
│  # 只能存储 int,需要写 StrBox、FloatBox...                 │
│                                                             │
│  泛型类:                                                    │
│  class Box(Generic[T]):                                     │
│      def __init__(self, item: T): ...                       │
│      def get(self) -> T: ...                                │
│  # 一个类存储所有类型:Box[int]、Box[str]、Box[User]...     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

代码示例:

python
from typing import TypeVar, Generic

T = TypeVar('T')

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

int_box: Box[int] = Box(42)
value: int = int_box.get()

str_box: Box[str] = Box("hello")
text: str = str_box.get()

关键代码解释:

代码含义为什么这样写
Generic[T]继承泛型基类,声明 T 为类型参数让类支持泛型,一个类处理多种类型
item: T参数类型为 T存入的类型与声明类型一致
-> T返回类型为 T取出的类型与存入类型一致
Box[int]使用时指定 T 为 int创建整数盒子,类型检查器知道内部是 int
Box[str]使用时指定 T 为 str创建字符串盒子,类型检查器知道内部是 str

1.5 渐进复杂

Python 3.12+ 新语法:泛型类参数语法

python
# Python 3.12+:直接在类定义中使用类型参数(无需 TypeVar)
class Stack[T]:
    """泛型栈(Python 3.12+ 新语法)"""
    
    def __init__(self) -> None:
        self._items: list[T] = []
    
    def push(self, item: T) -> None:
        self._items.append(item)
    
    def pop(self) -> T:
        if not self._items:
            raise IndexError("栈为空")
        return self._items.pop()

# Python 3.11 兼容写法(使用 TypeVar)
from typing import TypeVar, Generic

T = TypeVar('T')

class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []
    
    def push(self, item: T) -> None:
        self._items.append(item)
    
    def pop(self) -> T:
        if not self._items:
            raise IndexError("栈为空")
        return self._items.pop()

泛型约束:

python
from typing import TypeVar

Number = TypeVar('Number', int, float)

def double(value: Number) -> Number:
    return value * 2

result1 = double(5)      # int: 10
result2 = double(5.0)    # float: 10.0
# double("hello")        # 类型检查器警告!

关键代码解释:

代码含义为什么这样写
TypeVar('Number', int, float)定义约束类型变量Number 只能是 int 或 float,不能是其他类型
value: Number参数类型为 Number接收 int 或 float,但拒绝 str 等
-> Number返回类型为 Number返回类型与参数类型一致
double("hello")类型检查器警告字符串不满足 Number 的约束条件

多类型变量:

python
from typing import TypeVar, Generic

K = TypeVar('K')
V = TypeVar('V')

class Pair(Generic[K, V]):
    def __init__(self, key: K, value: V) -> None:
        self.key = key
        self.value = value
    
    def get_key(self) -> K:
        return self.key
    
    def get_value(self) -> V:
        return self.value

pair: Pair[str, int] = Pair("age", 25)
key: str = pair.get_key()
value: int = pair.get_value()

关键代码解释:

代码含义为什么这样写
K = TypeVar('K')定义类型变量 K用于键的类型
V = TypeVar('V')定义类型变量 V用于值的类型
Generic[K, V]多类型参数泛型K 和 V 可以是不同类型
Pair[str, int]K=str, V=int键是字符串,值是整数
key: str自动推断为 str与声明时 K=str 一致
value: int自动推断为 int与声明时 V=int 一致

1.6 实际应用

泛型栈:

python
from typing import TypeVar, Generic

T = TypeVar('T')

class Stack(Generic[T]):
    """泛型栈"""
    
    def __init__(self) -> None:
        self._items: list[T] = []
    
    def push(self, item: T) -> None:
        """入栈"""
        self._items.append(item)
    
    def pop(self) -> T:
        """出栈"""
        if not self._items:
            raise IndexError("栈为空")
        return self._items.pop()
    
    def peek(self) -> T:
        """查看栈顶"""
        if not self._items:
            raise IndexError("栈为空")
        return self._items[-1]
    
    def is_empty(self) -> bool:
        return len(self._items) == 0

# 整数栈
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
print(int_stack.pop())  # 2

# 字符串栈
str_stack: Stack[str] = Stack()
str_stack.push("a")
str_stack.push("b")
print(str_stack.pop())  # "b"

泛型仓储:

python
from typing import TypeVar, Generic
from dataclasses import dataclass

T = TypeVar('T')

@dataclass
class Entity:
    id: int

class Repository(Generic[T]):
    """泛型仓储"""
    
    def __init__(self) -> None:
        self._storage: list[T] = []
    
    def add(self, item: T) -> int:
        """添加并返回索引"""
        self._storage.append(item)
        return len(self._storage) - 1
    
    def get(self, index: int) -> T | None:
        """按索引获取"""
        if 0 <= index < len(self._storage):
            return self._storage[index]
        return None
    
    def get_all(self) -> list[T]:
        """获取所有"""
        return self._storage.copy()

# 使用
class User(Entity):
    def __init__(self, id: int, name: str) -> None:
        super().__init__(id)
        self.name = name

user_repo: Repository[User] = Repository()
user_repo.add(User(1, "张三"))
user_repo.add(User(2, "李四"))

user = user_repo.get(0)
if user:
    print(f"用户:{user.name}")

2. 协议 Protocol

2.1 问题引入

场景: 你想定义"有 draw 方法的对象",但不关心具体类型。

python
# 如何定义"有 draw 方法的类型"?
def render(shape):
    shape.draw()  # 希望任何有 draw 方法的对象都能用

# 传统继承方式:需要显式继承
class ShapeBase:
    def draw(self) -> None: ...

class Circle(ShapeBase):
    def draw(self) -> None:
        print("画圆")

# 问题:已有的类没有继承 ShapeBase,能用吗?
class ExistingCircle:
    def draw(self) -> None:
        print("画圆")

# render(ExistingCircle())  # 类型检查器可能警告

问题: 如何定义"有某种方法"的类型,而不要求显式继承?


2.2 概念解释

协议(Protocol): 基于方法的类型,只要有这些方法就符合。

┌─────────────────────────────────────────────────────┐
│          协议语法结构                                │
├─────────────────────────────────────────────────────┤
│                                                     │
│  定义协议:                                          │
│  ───────────────────────────────────────           │
│  class Drawable(Protocol):                         │
│              ↑                                      │
│           必须继承 Protocol                          │
│      def draw(self) -> None: ...                   │
│                        ↑                            │
│                     方法签名(...表示空实现)        │
│                                                     │
│  实现类:                                            │
│  ───────────────────────────────────────           │
│  class Circle:              # 无需继承 Drawable     │
│      def draw(self) -> None:   # 只要有方法即可     │
│          ...                                        │
│                                                     │
│  使用示例 → 解释:                                   │
│  render(Circle())  → Circle 有 draw,符合协议       │
│  render(123)       → int 无 draw,类型检查器警告    │
│                                                     │
│  核心特点:                                          │
│  • 结构化类型(鸭子类型)                            │
│  • 无需显式继承                                      │
│  • 只要有方法就符合                                  │
│                                                     │
└─────────────────────────────────────────────────────┘

2.3 最简示例

python
from typing import Protocol

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

class Circle:
    def draw(self) -> None:
        print("画圆")

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

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

render(Circle())
render(Square())

关键代码解释

代码含义为什么这样写
class Drawable(Protocol)定义协议类Protocol 表示这是一个协议,不是普通类
def draw(self) -> None: ...声明方法签名... 表示方法体为空,只声明不实现
class Circle普通类无需继承 Drawable,自动符合协议
def draw(self) -> None实现方法只要有 draw 方法,就符合 Drawable 协议
shape: Drawable参数类型为协议任何有 draw 方法的对象都可以传入
render(Circle())Circle 符合 Drawable因为 Circle 有 draw 方法

2.4 详细说明

定义协议:

python
from typing import Protocol

# 协议定义:列出方法签名
class Comparable(Protocol):
    def compare_to(self, other: "Comparable") -> int:
        """返回:负数、零、正数"""
        ...

class Sized(Protocol):
    def __len__(self) -> int: ...

class Iterable(Protocol):
    def __iter__(self) -> "Iterable": ...

协议继承:

python
from typing import Protocol

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

class Fillable(Protocol):
    def fill(self) -> None: ...

# 组合协议
class Shape(Drawable, Fillable, Protocol):
    def move(self, x: int, y: int) -> None: ...

# 实现类:需要所有方法
class Circle:
    def draw(self) -> None:
        print("画圆")
    
    def fill(self) -> None:
        print("填充圆")
    
    def move(self, x: int, y: int) -> None:
        print(f"移动到 ({x}, {y})")

def render_shape(shape: Shape) -> None:
    shape.draw()
    shape.fill()
    shape.move(0, 0)

render_shape(Circle())

2.5 渐进复杂

运行时检查:

python
from typing import Protocol, runtime_checkable

@runtime_checkable
class Serializable(Protocol):
    def to_json(self) -> str: ...

class User:
    def to_json(self) -> str:
        return '{"name": "张三", "age": 25}'

class PlainClass:
    pass

# 可以用 isinstance 检查
print(isinstance(User(), Serializable))      # True
print(isinstance(PlainClass(), Serializable))  # False

协议属性:

python
from typing import Protocol

class Named(Protocol):
    name: str  # 属性协议

class Person:
    def __init__(self, name: str) -> None:
        self.name = name

def greet(obj: Named) -> str:
    return f"你好,{obj.name}"

greet(Person("张三"))  # "你好,张三"

2.6 实际应用

可比较协议:

python
from typing import Protocol

class Comparable(Protocol):
    def compare_to(self, other: "Comparable") -> int: ...

class Person:
    def __init__(self, name: str, age: int) -> None:
        self.name = name
        self.age = age
    
    def compare_to(self, other: "Person") -> int:
        return self.age - other.age
    
    def __repr__(self) -> str:
        return f"Person({self.name}, {self.age})"

def find_max(items: list[Comparable]) -> Comparable:
    """找到最大的元素"""
    if not items:
        raise ValueError("列表为空")
    max_item = items[0]
    for item in items[1:]:
        if item.compare_to(max_item) > 0:
            max_item = item
    return max_item

# 使用
people = [
    Person("张三", 25),
    Person("李四", 18),
    Person("王五", 30)
]

max_person = find_max(people)
print(max_person)  # Person(王五, 30)

3. TypedDict 字典类型

3.1 问题引入

场景: 字典的每个字段有不同类型,如何标注?

python
# 普通字典注解:只知道是 dict
user: dict[str, str | int] = {
    "name": "张三",
    "age": 25,
    "email": "test@example.com"
}

# 问题:不知道哪些字段是必需的
# 问题:不知道每个字段的具体类型
name = user["name"]  # 类型是 str | int,不够精确

问题: 如何精确标注字典的每个字段类型?


3.2 概念解释

TypedDict: 定义字典的键名和每个键的类型。

┌─────────────────────────────────────────────────────┐
│          TypedDict 语法结构                          │
├─────────────────────────────────────────────────────┤
│                                                     │
│  定义 TypedDict:                                    │
│  ───────────────────────────────────────           │
│  class UserDict(TypedDict):                        │
│              ↑                                      │
│           必须继承 TypedDict                         │
│      id: int        # 字段名 + 类型                  │
│      name: str      # 字段名 + 类型                  │
│      email: str     # 字段名 + 类型                  │
│                                                     │
│  可选字段:                                          │
│  ───────────────────────────────────────           │
│  class UserDict(TypedDict, total=False):           │
│                              ↑                      │
│                      所有字段变为可选                │
│                                                     │
│  使用示例 → 解释:                                   │
│  user["id"]     → IDE 知道返回 int                  │
│  user["name"]   → IDE 知道返回 str                  │
│  user["age"]    → 类型检查器警告:未定义的字段       │
│                                                     │
│  对比普通 dict[str, Any]:                           │
│  • 精确标注每个字段类型                              │
│  • IDE 提示字段名                                    │
│  • 类型检查器验证字段                                │
│                                                     │
└─────────────────────────────────────────────────────┘

3.3 最简示例

python
from typing import TypedDict

class UserDict(TypedDict):
    id: int
    name: str
    email: str

user: UserDict = {
    "id": 1,
    "name": "张三",
    "email": "test@example.com"
}

print(user["id"])
print(user["name"])

关键代码解释

代码含义为什么这样写
class UserDict(TypedDict)定义字典类型类TypedDict 不是普通类,是类型声明工具
id: int字段名和类型声明 id 字段必须是 int 类型
name: str字段名和类型声明 name 字段必须是 str 类型
email: str字段名和类型声明 email 字段必须是 str 类型
user: UserDict变量类型为 UserDict类型检查器会验证字典内容是否符合定义
user["id"]访问字段IDE 知道返回值是 int 类型(精确类型)

3.4 详细说明

必需字段:

python
from typing import TypedDict

class UserDict(TypedDict):
    """所有字段都是必需的"""
    id: int
    name: str
    email: str

# 缺少字段会报错
# user: UserDict = {"id": 1}  # 类型检查器警告

可选字段:

python
from typing import TypedDict

class UserDict(TypedDict, total=False):
    """所有字段都是可选的"""
    id: int
    name: str
    email: str

# 可以只有部分字段
user: UserDict = {"id": 1}  # 正确

混合必需和可选:

python
from typing import TypedDict

class UserDict(TypedDict):
    """必需字段"""
    id: int
    name: str

class UserDictFull(UserDict, total=False):
    """继承并添加可选字段"""
    email: str | None
    age: int | None

# 使用
user1: UserDictFull = {"id": 1, "name": "张三"}  # 正确
user2: UserDictFull = {
    "id": 1,
    "name": "张三",
    "email": "test@example.com",
    "age": 25
}

3.5 渐进复杂

ReadOnly(Python 3.11+):

python
from typing import TypedDict, ReadOnly

class ConfigDict(TypedDict):
    host: ReadOnly[str]    # 不可修改
    port: ReadOnly[int]    # 不可修改
    debug: bool            # 可修改

config: ConfigDict = {
    "host": "localhost",
    "port": 8080,
    "debug": False
}

config["debug"] = True   # 正确
# config["port"] = 9000  # 类型检查器警告:ReadOnly

3.6 实际应用

API 响应类型:

python
from typing import TypedDict

class APIResponse(TypedDict):
    status: str
    code: int
    message: str

class UserData(TypedDict):
    id: int
    name: str
    email: str

class UserResponse(APIResponse):
    data: UserData

def get_user_response(user_id: int) -> UserResponse:
    return {
        "status": "success",
        "code": 200,
        "message": "获取成功",
        "data": {
            "id": user_id,
            "name": "张三",
            "email": "test@example.com"
        }
    }

response = get_user_response(1)
print(response["data"]["name"])  # "张三"

3.7 TypedDict 最佳实践

推荐做法

做法原因示例
API 响应用 TypedDict精确标注每个字段class APIResponse(TypedDict):
必需字段不加 total=False默认行为更安全class User(TypedDict): id: int
继承扩展可选字段分层定义更清晰class UserFull(User, total=False):
ReadOnly 保护关键字段防止意外修改id: ReadOnly[int]
嵌套 TypedDict表达复杂结构data: UserData

反模式

python
# ❌ 所有字段都可选
class User(TypedDict, total=False):
    id: int      # id 应该是必需的!
    name: str

# ✅ 正确:必需字段单独定义
class User(TypedDict):
    id: int      # 必需
    name: str    # 必需

class UserOptional(User, total=False):
    email: str   # 可选
python
# ❌ 用 dict[str, Any] 代替 TypedDict
user: dict[str, Any] = {"id": 1, "name": "张三"}
name = user["name"]  # 类型是 Any,无 IDE 提示

# ✅ 正确:用 TypedDict
class UserDict(TypedDict):
    id: int
    name: str

user: UserDict = {"id": 1, "name": "张三"}
name = user["name"]  # 类型是 str,有 IDE 提示
python
# ❌ TypedDict 定义方法
class User(TypedDict):
    id: int
    name: str
    
    def get_name(self) -> str:  # TypedDict 不支持方法!
        return self["name"]

# ✅ 正确:TypedDict 只定义字段,方法写在独立类
class User(TypedDict):
    id: int
    name: str

class UserEntity:
    def __init__(self, data: User) -> None:
        self.data = data
    
    def get_name(self) -> str:
        return self.data["name"]

适用场景

场景是否推荐 TypedDict原因
API 响应/请求✅ 推荐字段固定,类型明确
JSON 数据结构✅ 推荐精确标注每个字段
配置文件结构✅ 推荐字段名和类型清晰
数据库记录映射✅ 推荐字段类型固定
动态字段结构❌ 用 dict[str, Any]字段不确定
需要方法/行为❌ 用 dataclassTypedDict 只存数据
需要默认值❌ 用 dataclassTypedDict 无默认值
需要验证逻辑❌ 用 PydanticTypedDict 无验证

4. 运行时类型检查

4.1 问题引入

场景: 类型提示默认不运行时检查,如何验证参数类型?

python
def greet(name: str) -> str:
    return f"Hello, {name}"

# 类型提示不阻止错误
greet(123)  # 运行成功(虽然类型不对)

# 问题:如何在运行时验证类型?

4.2 概念解释

get_type_hints: 获取函数的类型注解信息。

┌─────────────────────────────────────────────────────┐
│          运行时类型检查语法                          │
├─────────────────────────────────────────────────────┤
│                                                     │
│  获取类型提示:                                      │
│  ───────────────────────────────────────           │
│  get_type_hints(func)                              │
│  → 返回 {'name': str, 'age': int, 'return': str}   │
│                                                     │
│  解析泛型类型:                                      │
│  ───────────────────────────────────────           │
│  get_origin(list[int])    → list                   │
│  get_args(list[int])      → (int,)                 │
│  get_origin(dict[str, int]) → dict                 │
│  get_args(dict[str, int]) → (str, int)             │
│                                                     │
│  使用示例 → 解释:                                   │
│  hints['name']  → 获取 name 参数的类型              │
│  hints['return'] → 获取返回值类型                   │
│  get_origin(x)  → 获取泛型的"外壳"(如 list)       │
│  get_args(x)    → 获取泛型的"内容"(如 int)        │
│                                                     │
│  应用场景:                                          │
│  • 运行时参数验证                                    │
│  • 动态类型检查                                      │
│  • API 数据验证                                      │
│                                                     │
└─────────────────────────────────────────────────────┘

4.3 最简示例

python
from typing import get_type_hints

def greet(name: str, age: int) -> str:
    return f"Hello {name}, you are {age}"

# 获取类型提示
hints = get_type_hints(greet)
print(hints)
# {'name': <class 'str'>, 'age': <class 'int'>, 'return': <class 'str'>}

# 查看具体类型
print(f"name 参数: {hints['name']}")    # str
print(f"age 参数: {hints['age']}")      # int
print(f"返回值: {hints['return']}")     # str

4.4 详细说明

手动验证装饰器:

python
from typing import get_type_hints, get_origin, get_args, Union
import functools

def validate_args(func):
    """运行时参数类型验证"""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        hints = get_type_hints(func)
        
        # 检查参数
        for i, (arg_name, arg_value) in enumerate(zip(hints.keys(), args)):
            if arg_name == 'return':
                continue
            expected_type = hints[arg_name]
            if not isinstance(arg_value, expected_type):
                raise TypeError(
                    f"参数 '{arg_name}' 类型错误: "
                    f"期望 {expected_type.__name__}, 实际 {type(arg_value).__name__}"
                )
        
        return func(*args, **kwargs)
    return wrapper

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

# 测试
print(add(1, 2))        # 3
# add("1", 2)          # TypeError: 参数 'a' 类型错误

4.5 渐进复杂

完整类型检查器:

python
from typing import get_type_hints, get_origin, get_args, Union
from dataclasses import dataclass

class TypeChecker:
    """类型检查工具"""
    
    @staticmethod
    def check(value: any, expected: any) -> bool:
        """检查单个值"""
        # None 检查
        if expected is type(None):
            return value is None
        
        # Union 类型
        origin = get_origin(expected)
        if origin is Union:
            args = get_args(expected)
            return isinstance(value, args) or value is None
        
        # 泛型容器
        if origin:
            return isinstance(value, origin)
        
        # 基本类型
        return isinstance(value, expected)
    
    @classmethod
    def validate(cls, obj: any, hints: dict) -> dict[str, list[str]]:
        """验证对象字段"""
        errors: dict[str, list[str]] = {}
        
        for field_name, expected_type in hints.items():
            if hasattr(obj, field_name):
                value = getattr(obj, field_name)
                if not cls.check(value, expected_type):
                    errors[field_name] = [
                        f"期望 {expected_type}, 得到 {type(value).__name__}"
                    ]
        
        return errors

# 使用
@dataclass
class User:
    name: str
    age: int
    email: str | None = None

user = User(name="张三", age=25)
hints = {"name": str, "age": int, "email": str | None}

errors = TypeChecker.validate(user, hints)
if errors:
    print("验证失败:", errors)
else:
    print("验证通过")

4.6 实际应用

API 参数验证:

python
from typing import get_type_hints, TypedDict

class RequestData(TypedDict):
    user_id: int
    action: str

def validate_request(data: dict) -> RequestData:
    """验证请求数据"""
    required_fields = {"user_id": int, "action": str}
    
    for field, expected_type in required_fields.items():
        if field not in data:
            raise ValueError(f"缺少必需字段: {field}")
        if not isinstance(data[field], expected_type):
            raise TypeError(
                f"字段 '{field}' 类型错误: "
                f"期望 {expected_type.__name__}"
            )
    
    return data

def process_request(data: RequestData) -> str:
    """处理请求"""
    return f"处理用户 {data['user_id']}{data['action']} 请求"

# 使用
valid_data = validate_request({"user_id": 1, "action": "login"})
result = process_request(valid_data)
print(result)  # "处理用户 1 的 login 请求"

4.7 运行时类型检查最佳实践

推荐做法

做法原因示例
简单验证用 isinstance内置函数,最快isinstance(x, int)
API 边界验证数据防止外部错误数据validate_request(data)
验证装饰器复用逻辑一处定义,多处使用@validate_args
使用 Pydantic 替代复杂验证功能强大,生态完善BaseModel
避免递归检查大容器性能开销大只检查外壳类型

反模式

python
# ❌ 类型提示误认为运行时检查
def add(a: int, b: int) -> int:
    return a + b

add("1", "2")  # 运行正常!类型提示不阻止执行

# ✅ 正确:需要验证时手动检查或用 Pydantic
def add(a: int, b: int) -> int:
    if not isinstance(a, int) or not isinstance(b, int):
        raise TypeError("参数必须是整数")
    return a + b
python
# ❌ 完整验证所有嵌套元素(性能差)
def validate_every_element(data: list[list[int]]) -> bool:
    for row in data:
        for elem in row:
            if not isinstance(elem, int):
                return False
    return True

# ✅ 正确:只验证外壳,信任内部类型(或用 Pydantic)
def validate_structure(data: list[list[int]]) -> bool:
    return isinstance(data, list) and all(isinstance(row, list) for row in data)
python
# ❌ 用 get_type_hints 过度验证内部函数
def internal_helper(x: int) -> str:
    return str(x)

# 内部函数不需要运行时验证
# 类型检查器静态分析就够了

# ✅ 正确:只在边界(API入口)验证
def api_endpoint(data: dict[str, Any]) -> Result:
    # API 入口验证
    if not isinstance(data.get("id"), int):
        raise ValueError("id 必须是整数")
    # 内部逻辑信任类型
    return process(data)

适用场景

场景是否推荐运行时验证原因
API 入口数据✅ 推荐外部数据不可信
用户输入验证✅ 推荐防止错误输入
配置文件加载✅ 推荐验证配置正确性
内部函数调用❌ 不推荐类型检查器已静态分析
性能敏感场景❌ 不推荐验证有开销
复杂嵌套结构用 Pydantic手写验证复杂易错

替代方案:Pydantic(推荐用于生产)

python
from pydantic import BaseModel, Field

class User(BaseModel):
    id: int = Field(gt=0)           # 验证:必须大于 0
    name: str = Field(min_length=1) # 验证:至少 1 字符
    email: str | None = None

# 自动验证
user = User(id=1, name="张三")
# user = User(id=-1, name="")  # ValidationError

# Pydantic 优势:
# • 自动运行时验证
# • 类型转换("123" → 123)
# • 详细错误信息
# • JSON 序列化/反序列化
# • 生态完善(FastAPI 集成)

5. 类型守卫

5.1 问题引入

场景: 检查了类型后,类型检查器仍然不知道类型已收窄。

python
def process(items: list[object]) -> str:
    # 检查是否全是字符串
    if all(isinstance(x, str) for x in items):
        # 类型检查器仍然认为 items 是 list[object]
        return " ".join(items)  # 类型检查器可能警告
    return "不是字符串列表"

问题: 如何告诉类型检查器"检查后类型已收窄"?


5.2 概念解释

TypeGuard: 标注类型检查函数,告诉类型检查器类型已收窄。

┌─────────────────────────────────────────────────────┐
│          TypeGuard 语法结构                          │
├─────────────────────────────────────────────────────┤
│                                                     │
│  定义类型守卫函数:                                  │
│  ───────────────────────────────────────           │
│  def is_str_list(val: list[object]) -> TypeGuard[list[str]]:
│                                        ↑            │
│                                  返回类型守卫        │
│      return all(isinstance(x, str) for x in val)   │
│                                                     │
│  使用示例 → 解释:                                   │
│  if is_str_list(items):                            │
│      # items 类型从 list[object] 收窄为 list[str]  │
│      return " ".join(items)  # 类型检查器认可       │
│                                                     │
│  核心特点:                                          │
│  • 返回 True → 类型收窄为具体类型                    │
│  • 返回 False → 类型保持不变                        │
│  • 用于复杂类型检查(isinstance 无法处理的)         │
│                                                     │
│  适用场景:                                          │
│  • 检查列表元素类型                                  │
│  • 检查字典字段类型                                  │
│  • 检查嵌套结构类型                                  │
│                                                     │
└─────────────────────────────────────────────────────┘

5.3 最简示例

python
from typing import TypeGuard

def is_string_list(val: list[object]) -> TypeGuard[list[str]]:
    """类型守卫:检查是否为字符串列表"""
    return all(isinstance(x, str) for x in val)

def process(items: list[object]) -> str:
    if is_string_list(items):
        # 类型检查器知道 items 是 list[str]
        return " ".join(items)  # 正确!
    return "不是字符串列表"

# 使用
print(process(["a", "b", "c"]))  # "a b c"
print(process([1, "b", 3]))      # "不是字符串列表"

5.4 详细说明

TypeGuard vs isinstance:

python
from typing import TypeGuard

def process(value: int | str) -> str:
    # isinstance 自动收窄类型
    if isinstance(value, int):
        return f"整数: {value * 2}"  # 类型检查器知道是 int
    elif isinstance(value, str):
        return f"字符串: {value.upper()}"  # 类型检查器知道是 str
    return ""

# TypeGuard 用于复杂类型检查
def is_positive_dict(val: dict[str, object]) -> TypeGuard[dict[str, int]]:
    """检查字典值是否为正整数"""
    return all(isinstance(v, int) and v > 0 for v in val.values())

def sum_values(data: dict[str, object]) -> int:
    if is_positive_dict(data):
        # 类型检查器知道 data 是 dict[str, int]
        return sum(data.values())
    return 0

5.5 渐进复杂

自定义类型守卫:

python
from typing import TypeGuard, Any

def is_user_dict(val: dict[str, Any]) -> TypeGuard[dict[str, str | int]]:
    """检查是否为用户字典"""
    required = {"id", "name"}
    return (
        all(k in val for k in required) and
        isinstance(val.get("id"), int) and
        isinstance(val.get("name"), str)
    )

def process_user(data: dict[str, Any]) -> str:
    if is_user_dict(data):
        return f"用户 ID: {data['id']}, 姓名: {data['name']}"
    return "无效用户数据"

# 使用
user_data = {"id": 1, "name": "张三", "email": "test@example.com"}
print(process_user(user_data))  # "用户 ID: 1, 姓名: 张三"

5.6 实际应用

数据处理管道:

python
from typing import TypeGuard, Any

def is_valid_row(row: list[Any]) -> TypeGuard[list[str | int]]:
    """检查数据行是否有效"""
    return len(row) == 3 and isinstance(row[0], str)

def is_complete_row(row: list[str | int]) -> TypeGuard[list[str | int | float]]:
    """检查数据行是否完整"""
    return all(isinstance(v, (str, int, float)) for v in row)

def process_data(rows: list[list[Any]]) -> list[str]:
    results: list[str] = []
    for row in rows:
        if is_valid_row(row):
            if is_complete_row(row):
                name, count, score = row
                results.append(f"{name}: {count} 条, 平均 {score}")
            else:
                results.append(f"{row[0]}: 数据不完整")
        else:
            results.append("无效行")
    return results

# 使用
data = [
    ["张三", 10, 85.5],
    ["李四", 5],
    [123]
]

results = process_data(data)
for r in results:
    print(r)

关键代码说明:

代码含义为什么这样写
-> TypeGuard[list[str | int]]返回类型守卫而非 boolTypeGuard 告知类型检查器:函数返回 True 时,参数类型被收窄为指定类型
if is_valid_row(row): 后可访问 row[0]类型守卫使类型收窄进入 if 块后,row 被收窄为 list[str | int],类型检查器不再报错
if is_complete_row(row): 嵌套守卫二次收窄类型两层守卫实现渐进式类型精化,内层代码可以安全解包 name, count, score = row
name, count, score = row解包赋值经过两层类型守卫后,可以安全解包并使用具体字段名,代码可读性更高

5.7 TypeGuard 最佳实践

推荐做法

做法原因示例
复杂类型检查用 TypeGuardisinstance 无法处理list[str]dict[str, int]
简单类型用 isinstance内置自动收窄if isinstance(x, int):
TypeGuard 函数命名 is_xxx表达"判断是否是"is_string_list
检查逻辑与类型一致返回 True 时类型正确检查所有元素
返回类型明确收窄结果类型检查器理解-> TypeGuard[list[str]]

反模式

python
# ❌ 简单类型使用 TypeGuard(没必要)
def is_int(val: object) -> TypeGuard[int]:
    return isinstance(val, int)

# ✅ 正确:简单类型直接用 isinstance
if isinstance(value, int):
    # 类型已自动收窄为 int
    pass
python
# ❌ TypeGuard 检查逻辑与返回类型不一致
def is_positive_list(val: list[object]) -> TypeGuard[list[int]]:
    return all(isinstance(x, int) for x in val)  # 没检查是否为正数!

# ✅ 正确:检查逻辑与类型一致
def is_positive_int_list(val: list[object]) -> TypeGuard[list[int]]:
    return all(isinstance(x, int) and x > 0 for x in val)
python
# ❌ TypeGuard 函数有副作用
def is_valid(data: dict) -> TypeGuard[ValidDict]:
    data["validated"] = True  # 不要修改数据!
    return True

# ✅ 正确:TypeGuard 只检查,不修改
def is_valid(data: dict) -> TypeGuard[ValidDict]:
    return "id" in data and isinstance(data["id"], int)
python
# ❌ 忽略 False 分支的类型
def process(items: list[object]) -> str:
    if is_string_list(items):
        return " ".join(items)  # items 是 list[str]
    else:
        return " ".join(items)  # items 仍是 list[object],可能报错

# ✅ 正确:False 分支类型不变
def process(items: list[object]) -> str:
    if is_string_list(items):
        return " ".join(items)
    else:
        return "不是字符串列表"  # 不使用 items 元素

适用场景

场景是否推荐 TypeGuard原因
检查列表元素类型✅ 推荐isinstance 无法处理
检查字典值类型✅ 推荐需要遍历验证
检查嵌套结构✅ 推荐复杂类型收窄
检查单个类型❌ 用 isinstance内置更简洁
检查 Union 类型❌ 用 isinstance自动收窄
检查 Optional 类型❌ 用 is None更简单

L2 实践层:用好

泛型设计最佳实践

推荐做法

做法原因示例
使用有意义的类型变量名提高代码可读性T = TypeVar('T') 用 T 表示通用类型
约束泛型范围防止传入不合适类型Number = TypeVar('Number', int, float)
泛型类方法保持类型一致确保类型安全get() -> Tset(item: T)
简单容器优先用内置泛型无需额外导入list[T]List[T] 更现代
复杂泛型使用类型别名简化重复类型`Result[T] = T
避免过度泛型化简单场景用具体类型只有 2 种类型不需要泛型

反模式:不要这样做

python
# ❌ 无意义的类型变量名
X = TypeVar('X')  # X 是什么?
Y = TypeVar('Y')  # Y 是什么?

# ✅ 正确做法:使用有意义的名称
Item = TypeVar('Item')      # 表示列表元素
Key = TypeVar('Key')        # 表示键
Value = TypeVar('Value')    # 表示值
python
# ❌ 泛型约束过于宽松
T = TypeVar('T')  # 任何类型都可以
def multiply(a: T, b: T) -> T:
    return a * b  # 如果 T 是 str,a * b 可能不是预期行为

# ✅ 正确做法:约束为数值类型
Number = TypeVar('Number', int, float, complex)
def multiply(a: Number, b: Number) -> Number:
    return a * b
python
# ❌ 过度泛型化
class StringProcessor(Generic[T]):
    def process(self, text: T) -> T:
        return text

# 实际只处理字符串,泛型没有意义

# ✅ 正确做法:直接使用具体类型
class StringProcessor:
    def process(self, text: str) -> str:
        return text
python
# ❌ 泛型类方法返回类型不一致
class Box(Generic[T]):
    def get(self) -> Any:  # 应该返回 T
        return self._item

# ✅ 正确做法:保持类型一致
class Box(Generic[T]):
    def get(self) -> T:
        return self._item

Protocol 使用最佳实践

推荐做法

做法原因示例
用 Protocol 定义接口契约明确对象需要实现的方法class Drawable(Protocol):
方法签名用 ... 空实现表示只声明不实现def draw(self) -> None: ...
组合多个 Protocol定义复杂接口class Shape(Drawable, Fillable, Protocol):
使用 @runtime_checkable 需要时才加运行时检查有性能开销@runtime_checkable class Serializable(Protocol):
Protocol 命名用形容词或能力表达"能做什么"Comparable, Iterable, Serializable

反模式:不要这样做

python
# ❌ Protocol 方法写实现代码
class Drawable(Protocol):
    def draw(self) -> None:
        print("画图")  # Protocol 不应有实现!

# ✅ 正确做法:只声明签名
class Drawable(Protocol):
    def draw(self) -> None: ...  # 空实现,只声明
python
# ❌ Protocol 继承普通类
class Drawable(BaseClass, Protocol):  # Protocol 不应继承非 Protocol 类
    pass

# ✅ 正确做法:只继承 Protocol 或其他 Protocol
class Drawable(Protocol):
    pass

class AdvancedDrawable(Drawable, Protocol):
    pass
python
# ❌ 不必要的 @runtime_checkable
@runtime_checkable
class Drawable(Protocol):
    def draw(self) -> None: ...

# 如果不需要 isinstance 检查,加 @runtime_checkable 是冗余的

# ✅ 正确做法:只在需要运行时检查时添加
class Drawable(Protocol):
    def draw(self) -> None: ...

# 需要运行时检查时
@runtime_checkable
class Serializable(Protocol):
    def to_json(self) -> str: ...

适用场景

场景是否推荐原因
定义插件接口✅ 推荐插件只需实现方法,无需继承基类
库的公共接口✅ 推荐用户代码可实现协议,无需导入基类
鸭子类型类型化✅ 推荐让鸭子类型有类型检查
已有类适配✅ 推荐无需修改已有类,自动符合协议
强制继承关系❌ 不推荐需要显式继承时用普通基类
需要共享实现❌ 不推荐Protocol 不提供实现,用抽象基类

L3 专家层:深入

泛型底层实现

Python 如何实现泛型

泛型内部机制:
┌─────────────────────────────────────────────────────┐
│  TypeVar 创建                                        │
│                                                      │
│  T = TypeVar('T')                                    │
│  ├── 创建 TypeVar 实例                               │
│  ├── 存储名称和约束                                  │
│  ├── 运行时只是一个标记对象                          │
│                                                      │
│  泛型类定义                                          │
│  ───────────────────────────────────────           │
│  class Box(Generic[T]):                             │
│      ├── Generic.__class_getitem__ 被调用           │
│      ├── 创建 _GenericAlias 对象                    │
│      ├── Box[int] 返回这个别名对象                  │
│                                                      │
│  类型检查器处理                                      │
│  ───────────────────────────────────────           │
│  ├── 静态分析时替换类型变量                          │
│  ├── Box[int] 中 T 替换为 int                       │
│  ├── 运行时不替换,只是标记                          │
└─────────────────────────────────────────────────────┘

演示代码

python
from typing import TypeVar, Generic, get_origin, get_args

T = TypeVar('T')

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

# 查看泛型类的内部结构
print(Box[int])  # __main__.Box[int]
print(type(Box[int]))  # typing._GenericAlias

# 解析泛型
print(get_origin(Box[int]))  # <class '__main__.Box'>
print(get_args(Box[int]))    # (<class 'int'>,)

# 运行时行为
box = Box(42)  # Box[int] 的实例
print(type(box))  # <class '__main__.Box'>
# 注意:运行时类型是 Box,不是 Box[int]

TypeVar 绑定机制

python
from typing import TypeVar

# 无约束 TypeVar
T = TypeVar('T')
# 可以是任何类型

# 约束 TypeVar
Number = TypeVar('Number', int, float)
# 只能是 int 或 float

# 有上界的 TypeVar
T_bound = TypeVar('T_bound', bound=SupportsInt)
# 必须是 SupportsInt 或其子类

# 查看约束
print(T.__constraints__)    # ()
print(Number.__constraints__)  # (int, float)
print(T_bound.__bound__)    # <class 'SupportsInt'>

运行时类型检查的实现

运行时检查流程:
┌─────────────────────────────────────────────────────┐
│  手动实现运行时检查                                  │
│                                                      │
│  步骤:                                              │
│  1. 获取类型提示                                     │
│     hints = get_type_hints(func)                    │
│                                                      │
│  2. 解析泛型类型                                     │
│     origin = get_origin(expected_type)              │
│     args = get_args(expected_type)                  │
│                                                      │
│  3. 执行类型检查                                     │
│     if origin:                                       │
│         check_generic(value, origin, args)          │
│     else:                                            │
│         isinstance(value, expected_type)            │
│                                                      │
│  限制:                                              │
│  ├── 泛型运行时只检查"外壳"                          │
│  ├── list[int] 检查 value 是 list                   │
│  ├── 不检查元素是否都是 int                          │
│  ├── 完整检查需要递归验证                            │
└─────────────────────────────────────────────────────┘

实现完整运行时检查

python
from typing import get_origin, get_args, Union
import inspect

def check_type(value: object, expected: type) -> bool:
    """完整的运行时类型检查"""
    # 处理 None 类型
    if expected is type(None):
        return value is None

    # 处理 Union 类型
    origin = get_origin(expected)
    if origin is Union:
        args = get_args(expected)
        return any(check_type(value, arg) for arg in args)

    # 处理泛型容器
    if origin is not None:
        # 检查外壳类型
        if not isinstance(value, origin):
            return False

        # 递归检查元素类型
        args = get_args(expected)
        if origin is list:
            return all(check_type(item, args[0]) for item in value)
        elif origin is dict:
            k_type, v_type = args
            return all(
                check_type(k, k_type) and check_type(v, v_type)
                for k, v in value.items()
            )
        elif origin is tuple:
            if len(args) == 2 and args[1] is ...:
                # 可变长度元组 tuple[int, ...]
                return all(check_type(item, args[0]) for item in value)
            else:
                # 固定长度元组
                return len(value) == len(args) and all(
                    check_type(v, t) for v, t in zip(value, args)
                )
        return True

    # 基本类型
    return isinstance(value, expected)

# 测试
print(check_type([1, 2, 3], list[int]))        # True
print(check_type([1, "a", 3], list[int]))      # False
print(check_type({"a": 1}, dict[str, int]))    # True
print(check_type({"a": "b"}, dict[str, int]))  # False

性能考量

操作时间复杂度空间复杂度说明
TypeVar 创建O(1)O(1)创建标记对象
泛型类定义O(1)O(1)创建类,存储类型参数
泛型实例化O(1)O(1)不比普通类慢
get_origin/get_argsO(1)O(1)访问内部属性
完整运行时检查O(n)O(1)n 为元素数量,递归检查
isinstance 单次检查O(1)O(1)不检查泛型内部

设计动机

设计选择原因替代方案对比
泛型运行时不检查保持性能,类型检查在静态分析时完成Java 泛型运行时擦除,类似设计
TypeVar 是标记对象简化实现,无需复杂类型系统Rust 泛型编译时展开,有运行时成本
Protocol 结构化类型鸭子类型的类型化,不强制继承Go 的接口类似,隐式实现
Generic 基类明确声明泛型类C++ 模板无需声明,编译器推断

知识关联

泛型知识关联:
                    ┌───────────────┐
                    │  类型检查器   │
                    │  静态分析     │
                    └───────────────┘


┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│  TypeVar      │────→│  Generic      │────→│  泛型类       │
│  类型变量     │     │  泛型基类     │     │  Box[T]       │
└───────────────┘     └───────────────┘     └───────────────┘
       │                     │                     │
       ↓                     ↓                     ↓
┌───────────────┐     ┌───────────────┐     ┌───────────────┐
│  约束         │     │  _GenericAlias│     │  运行时检查   │
│  bound        │     │  内部对象     │     │  手动实现     │
└───────────────┘     └───────────────┘     └───────────────┘

本章总结(完整版)

核心技能速查

技能说明示例
TypeVar类型变量T = TypeVar('T')
Generic泛型类class Stack(Generic[T]):
Protocol协议类型class Drawable(Protocol):
TypedDict字典类型class UserDict(TypedDict):
get_type_hints获取类型注解get_type_hints(func)
TypeGuard类型守卫-> TypeGuard[list[str]]

三层学习路线

类型进阶学习路线:
├── L1 理解层(会用)
│   ├── 第 1 步:掌握泛型函数(TypeVar + Generic)
│   ├── 第 2 步:学会泛型类设计
│   ├── 第 3 步:理解 Protocol 协议
│   ├── 第 4 步:使用 TypedDict 精确标注字典
│   └── 第 5 步:实现 TypeGuard 类型守卫

├── L2 实践层(用好)
│   ├── 泛型约束范围
│   ├── Protocol 接口设计
│   ├── 类型别名简化复杂泛型
│   └── 避免过度泛型化

└── L3 专家层(深入)
    ├── 理解 _GenericAlias 内部结构
    ├── TypeVar 绑定机制
    ├── 运行时类型检查实现
    └── 性能考量与设计动机