Vanson's Eternal Blog

Python中的Typing模块

Python typing.png
Published on
/9 mins read/---

typing 模块提供了许多高级特性,这些特性可以帮助开发者编写更健壮、更易维护的代码。 以下是一些高级用法的详细解析,结合了最新的 typing 模块功能和 typing-extensions 包的内容。

基础类型

Any:任意类型‌

表示变量可以是任何类型,‌完全禁用类型检查‌(慎用,优先用更具体的类型)。

from typing import Any
 
def print_anything(data: Any) -> None:
    print(data)  # 可以是 int、str、dict 等任意类型
 
print_anything(42)     # 合法
print_anything("hello")# 合法
 

Union:联合类型‌

表示变量可以是多个类型中的一种(Python 3.10+ 可用 | 替代)。

 
from typing import Union
 
def parse_input(data: Union[str, int]) -> str:
    return str(data)  # 接受 str 或 int,返回 str
 
# Python 3.10+ 等价写法
def parse_input_v2(data: str | int) -> str:
    return str(data)
 
print(parse_input(100))    # 输出 "100"
print(parse_input("abc")) # 输出 "abc"
 
 

Optional:可选类型‌

等价于 Union[T, None],表示变量可能是某个类型或 None。

 
from typing import Optional
 
def find_user(user_id: int) -> Optional[str]:
    if user_id == 1:
        return "Alice"  # 返回 str
    else:
        return None     # 返回 None
 
user = find_user(1)
if user is not None:
    print(user.upper())  # 类型检查器知道此处 user 是 str
 
 

容器类型

List/list:列表‌

指定列表元素的类型。

 
from typing import List
 
def sum_numbers(nums: List[int]) -> int:
    return sum(nums)  # 确保列表元素全是 int
 
# Python 3.9+ 内置泛型写法
def sum_numbers_v2(nums: list[int]) -> int:
    return sum(nums)
 
sum_numbers([1, 2, 3])  # 合法
sum_numbers(["a", "b"]) # 类型检查报错(元素不是 int)
 
 

Dict / dict:字典‌

指定键和值的类型。

 
from typing import Dict
 
def get_population() -> Dict[str, int]:
    return {"China": 1410, "India": 1380}  # 键为 str,值为 int
 
# Python 3.9+ 写法
def get_population_v2() -> dict[str, int]:
    return {"China": 1410, "India": 1380}
 
population = get_population()
print(population["China"] + 10)  # 类型检查器知道值是 int
 
 

Tuple / tuple:元组‌

  • ‌固定长度和类型‌:精确指定每个位置的类型。
  • ‌不定长元组‌:用 ... 表示剩余元素类型相同。
 
from typing import Tuple
 
def get_coordinates() -> Tuple[float, float]:
    return (40.7128, -74.0060)  # 两个 float 元素
 
# 不定长元组(Python 3.9+)
def process_data(data: tuple[int, ...]) -> int:
    return sum(data)  # 所有元素必须是 int
 
process_data((1, 2, 3))    # 合法
process_data((1, "a"))     # 类型检查报错(第二个元素不是 int)
 
 

Set / set:集合‌

指定集合元素的类型。

 
from typing import Set
 
def unique_values(items: Set[str]) -> int:
    return len(items)  # 元素必须是 str
 
# Python 3.9+ 写法
def unique_values_v2(items: set[str]) -> int:
    return len(items)
 
unique_values({"apple", "banana"})  # 合法
unique_values({1, 2})              # 类型检查报错
 
 

泛型与类型变量

TypeVar:定义泛型类型变量‌

创建可复用的泛型函数或类。

 
from typing import TypeVar, List
 
T = TypeVar('T')  # 可以是任何类型
 
def first_element(items: List[T]) -> T:
    return items  # 返回类型与列表元素类型相同
 
print(first_element([1, 2, 3]))    # 返回 int 类型(1)
print(first_element(["a", "b"]))   # 返回 str 类型("a")
 
 

Generic:泛型类‌

创建可参数化的类。

 
from typing import Generic, TypeVar, List
 
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:
        return self.items.pop()
 
# 实例化时指定具体类型
stack_int = Stack‌:ml-search[int]
stack_int.push(42)
stack_int.push("hello")  # 类型检查报错(非 int 类型)
 
stack_str = Stack‌:ml-search[str]
stack_str.push("world")  # 合法
 
 

函数与回调

Callable:函数签名‌

定义回调函数的参数和返回值类型。

 
from typing import Callable
 
def apply_operation(
    x: int, 
    y: int, 
    op: Callable[[int, int], int]  # 接受两个 int 参数,返回 int
) -> int:
    return op(x, y)
 
# 合法操作
print(apply_operation(3, 4, lambda a, b: a * b))  # 输出 12
 
# 非法操作(类型检查报错)
apply_operation(3, 4, lambda a: a)  # 回调函数参数数量不匹配
 
 

迭代器和生成器

  • Generator[YieldType, SendType, ReturnType]‌:定义生成器的产出值、发送值和返回值。
  • Iterable[T]‌:可迭代对象。
  • Iterable[T]‌:迭代器。
 
from typing import Generator, Iterable, Iterator
 
def count_up_to(n: int) -> Generator[int, None, None]:
    """生成器产出 int,不接收 send 值,无返回值"""
    i = 1
    while i <= n:
        yield i
        i += 1
 
def print_all(items: Iterable[str]) -> None:
    for item in items:
        print(item)
 
def square_numbers(nums: list[int]) -> Iterator[int]:
    return (num ** 2 for num in nums)  # 返回生成器表达式(迭代器)
 
# 使用示例
for num in count_up_to(5):
    print(num)  # 输出 1, 2, 3, 4, 5
 
 

高级类型

Literal

字面量类型(Python 3.8+)‌,限制变量只能取特定的字面量值。

from typing import Literal
 
def set_status(status: Literal["active", "inactive"]) -> None:
    print(f"Status set to {status}")
 
set_status("active")   # 合法
set_status("pending")  # 类型检查报错(不在允许的字面量中)
 
 

TypedDict

类型化字典(Python 3.8+)‌,定义字典的键和值类型,增强代码可读性和安全性。

 
from typing import TypedDict
 
class User(TypedDict):
    name: str
    age: int
    is_active: bool
 
def create_user() -> User:
    return {
        "name": "Bob",
        "age": 30,
        "is_active": True,
        "email": "bob@example.com"  # 类型检查报错(不在定义中)
    }
 
 

Protocol

结构子类型(Python 3.8+)‌,定义接口协议(无需继承,只要实现特定方法)。

 
from typing import Protocol
 
class Printable(Protocol):
    def print(self) -> None:
        ...  # 只需实现 print 方法即可符合协议
 
class Document:
    def print(self) -> None:
        print("Printing document...")
 
class Image:
    def print(self) -> None:
        print("Printing image...")
 
def log_print(obj: Printable) -> None:
    obj.print()
 
log_print(Document())  # 合法
log_print(Image())     # 合法
 
 

其他实用类型

NewType:创建新类型‌

定义具有语义的新类型(运行时无开销,仅用于类型检查)。

 
from typing import NewType
 
UserId = NewType("UserId", int)  # UserId 是 int 的派生类型
 
def get_user(id: UserId) -> str:
    return f"User {id}"
 
user_id = UserId(1001)  # 创建 UserId 类型变量
print(get_user(user_id))  # 合法
 
# 直接传递 int 会报错
print(get_user(1001))  # 类型检查报错(需要 UserId 类型)
 
 

Type:类类型‌

表示类本身(而非实例),常用于工厂模式。

 
from typing import Type
 
class Animal:
    def speak(self) -> str:
        return "..."
 
class Dog(Animal):
    def speak(self) -> str:
        return "Woof!"
 
def create_animal(cls: Type[Animal]) -> Animal:
    return cls()  # 创建类的实例
 
print(create_animal(Dog).speak())  # 输出 "Woof!"
 
 

Final

常量(Python 3.8+)‌,标记变量不可被重新赋值。

from typing import Final
 
MAX_SIZE: Final[int] = 100
MAX_SIZE = 200  # 类型检查报错(不可修改)
 
 

Annotated

Annotated 允许你在类型提示中添加元数据,这可以用于验证或文档目的。

from typing import Annotated
 
def process_value(value: Annotated[int, "Must be a positive integer"]) -> int:
    if value < 0:
        raise ValueError("Value must be positive!")
    return value
 
print(process_value(10))  # 正确
# print(process_value(-1))  # 会抛出 ValueError
 

Self

Self 类型简化了返回当前实例的方法的类型注解。

from typing import Self
 
class Builder:
    def __init__(self):
        self.data = []
 
    def add(self, value: int) -> Self:
        self.data.append(value)
        return self
 
builder = Builder().add(10).add(20)
print(builder.data)  # 输出: [10, 20]
 

Unpack 和变长泛型

Unpack 用于变长泛型,允许你解包类型序列。

 
from typing import TypeVarTuple, Unpack
 
Shape = TypeVarTuple("Shape")
 
def print_shapes(*shapes: Unpack[Shape]) -> None:
    for shape in shapes:
        print(shape)
 
print_shapes(1, 2, 3)  # 正确
 

协变与逆变

协变(Covariant)‌

允许子类替代父类(常见于只读容器)。

 
from typing import TypeVar, Generic
 
class Animal: pass
class Dog(Animal): pass
 
T_co = TypeVar("T_co", covariant=True)
 
class ImmutableList(Generic[T_co]):
    def __init__(self, items: list[T_co]) -> None:
        self.items = items
    
    def get(self, index: int) -> T_co:
        return self.items[index]
 
# 协变允许将 ImmutableList[Dog] 赋值给 ImmutableList[Animal]
animals: ImmutableList[Animal] = ImmutableList([Dog(), Dog()])
 
 

逆变(Contravariant)‌

允许父类替代子类(常见于函数参数)。

 
from typing import TypeVar, Generic, Callable
 
class Animal: pass
class Dog(Animal): pass
 
T_contra = TypeVar("T_contra", contravariant=True)
 
class EventHandler(Generic[T_contra]):
    def handle(self, data: T_contra) -> None:
        print(f"Handling {type(data).__name__}")
 
# 逆变允许将 EventHandler[Animal] 赋值给 EventHandler[Dog]
def process_event(handler: EventHandler[Dog]) -> None:
    handler.handle(Dog())
 
animal_handler = EventHandler‌:ml-search[Animal]
process_event(animal_handler)  # 合法