1. 模块概述
typing
模块在 python 3.5 中引入,用于支持类型提示(type hints)。它提供了:
- 用于类型注释的工具
- 泛型类型支持
- 类型别名
- 回调协议
- 以及其他高级类型系统特性
2. 基础类型提示
2.1 基本类型注释
from typing import list, dict, set, tuple, optional # 变量类型注释 name: str = "alice" age: int = 30 is_student: bool = false # 函数参数和返回值类型注释 def greet(name: str) -> str: return f"hello, {name}" # 容器类型 numbers: list[int] = [1, 2, 3] person: dict[str, str] = {"name": "alice", "email": "alice@example.com"} unique_numbers: set[int] = {1, 2, 3} coordinates: tuple[float, float] = (10.5, 20.3) # 可选类型 maybe_name: optional[str] = none # 等同于 union[str, none]
2.2 类型别名
from typing import list, tuple # 创建类型别名 vector = list[float] point = tuple[float, float] def scale_vector(v: vector, factor: float) -> vector: return [x * factor for x in v] def distance(p1: point, p2: point) -> float: return ((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)**0.5
3. 复合类型
3.1 union 类型
- 表示属于union中的任意一种类型均合法
from typing import union def process_value(value: union[int, str]) -> none: if isinstance(value, int): print(f"processing integer: {value}") else: print(f"processing string: {value}") process_value(10) # processing integer: 10 process_value("hi") # processing string: hi
3.2 optional 类型
- optional[str] = union[str, none]
from typing import optional def find_user(user_id: int) -> optional[str]: users = {1: "alice", 2: "bob"} return users.get(user_id) print(find_user(1)) # alice print(find_user(3)) # none
3.3 any 类型
- 表示可以使用任何类型,不建议常用
from typing import any def process_any(value: any) -> any: print(f"processing {value}") return value result = process_any(10) # processing 10 result = process_any("text") # processing text
4. 泛型类型
4.1 typevar
from typing import typevar, list, sequence t = typevar('t') # 任意类型 num = typevar('num', int, float) # 仅限于int和float def first_element(items: sequence[t]) -> t: return items[0] print(first_element([1, 2, 3])) # 1 print(first_element(["a", "b"])) # a
4.2 generic 类
from typing import typevar, generic, 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() int_stack = stack[int]() int_stack.push(1) int_stack.push(2) print(int_stack.pop()) # 2
5. 函数类型
5.1 callable
from typing import callable def apply_func(func: callable[[int, int], int], a: int, b: int) -> int: return func(a, b) def add(x: int, y: int) -> int: return x + y print(apply_func(add, 3, 5)) # 8
5.2 可调用对象协议
from typing import protocol class adder(protocol): def __call__(self, a: int, b: int) -> int: ... def apply_adder(adder: adder, x: int, y: int) -> int: return adder(x, y) print(apply_adder(lambda a, b: a + b, 10, 20)) # 30
6. 带元数据的类型annotated
annotated
是 python typing
模块中一个强大但常被忽视的类型注解工具,它允许我们在类型提示中添加额外的元数据。这个功能在 python 3.9 中引入,为类型系统提供了更大的灵活性。annotated
的基本形式如下:
from typing import annotated annotated[<type>, <metadata1>, <metadata2>, ...]
其中:
<type>
是基础类型<metadata>
可以是任意对象,提供额外的类型信息
6.1 基本示例
from typing import annotated # 给int类型添加单位信息 distance = annotated[int, "meters"] temperature = annotated[float, "celsius"] def get_distance() -> distance: return 100 def get_temperature() -> temperature: return 25.5
6.2 核心特性
- 保留类型信息
annotated
不会改变原始类型,只是附加元数据:
from typing import annotated, get_type_hints userid = annotated[int, "user identifier"] def get_user(id: userid) -> str: return f"user_{id}" # 获取类型提示 hints = get_type_hints(get_user) print(hints) # {'id': typing.annotated[int, 'user identifier'], 'return': <class 'str'>}
- 多重元数据
可以附加多个元数据项:
from typing import annotated # 带有范围和单位的温度类型 boundedtemp = annotated[float, "celsius", (0.0, 100.0)] def check_temp(temp: boundedtemp) -> bool: return 0.0 <= temp <= 100.0
6.3 应用场景
- 数据验证
结合 pydantic 等库进行数据验证:
from typing import annotated from pydantic import basemodel, field positiveint = annotated[int, field(gt=0)] class user(basemodel): id: positiveint name: str # 有效数据 user = user(id=1, name="alice") # 无效数据会引发验证错误 # user = user(id=-1, name="bob") # 抛出validationerror
- 参数约束
在 fastapi 等框架中指定参数约束:
from typing import annotated from fastapi import fastapi, query app = fastapi() @app.get("/items/") async def read_items( q: annotated[str, query(min_length=3, max_length=50)] = "default" ): return {"q": q}
- 文档增强
为类型添加文档信息:
from typing import annotated from typing_extensions import doc # python 3.11+ databaseconnection = annotated[ str, doc("a connection string in the format 'user:password@host:port/database'"), doc("example: 'admin:secret@localhost:5432/mydb'") ] def connect_db(conn_str: databaseconnection) -> none: """connect to the database.""" print(f"connecting with: {conn_str}")
6.4 与其他类型工具结合
- 与 newtype 结合
from typing import annotated, newtype userid = newtype('userid', int) annotateduserid = annotated[userid, "primary key"] def get_user_name(user_id: annotateduserid) -> str: return f"user_{user_id}" print(get_user_name(userid(42))) # user_42
- 与 literal 结合
from typing import annotated, literal httpmethod = literal["get", "post", "put", "delete"] annotatedhttpmethod = annotated[httpmethod, "http method"] def log_request(method: annotatedhttpmethod) -> none: print(f"received {method} request") log_request("get") # 有效 # log_request("head") # 类型检查器会报错
6.5 运行时访问元数据
from typing import annotated, get_type_hints def extract_metadata(annotated_type): origin = get_origin(annotated_type) if origin is not annotated: return none return get_args(annotated_type)[1:] # 返回元数据部分 # 定义带注解的类型 count = annotated[int, "counter", "must be positive"] hints = get_type_hints(lambda x: x, localns={'x': count}) metadata = extract_metadata(hints['x']) print(metadata) # ('counter', 'must be positive')
6.6. 实际案例:数据库字段类型
from typing import annotated, optional from datetime import datetime # 定义带约束的字段类型 username = annotated[str, "username", "max_length=32", "alphanumeric"] email = annotated[str, "email", "max_length=255"] createdat = annotated[datetime, "auto_now_add=true"] updatedat = annotated[optional[datetime], "auto_now=true", "nullable=true"] class userprofile: def __init__( self, username: username, email: email, created_at: createdat, updated_at: updatedat = none ): self.username = username self.email = email self.created_at = created_at self.updated_at = updated_at # 这些注解可以被orm框架或序列化库读取并使用
annotated
为 python 的类型系统提供了强大的扩展能力,使得类型提示不仅可以用于静态检查,还能携带丰富的运行时信息,为框架开发和复杂系统设计提供了更多可能性。
7. 高级类型特性
7.1 literal 类型
from typing import literal def draw_shape(shape: literal["circle", "square", "triangle"]) -> none: print(f"drawing a {shape}") draw_shape("circle") # 正确 draw_shape("square") # 正确 # draw_shape("rectangle") # 类型检查器会报错
7.2 typeddict
from typing import typeddict, optional class person(typeddict): name: str age: int email: optional[str] alice: person = {"name": "alice", "age": 30} bob: person = {"name": "bob", "age": 25, "email": "bob@example.com"}
7.3 newtype
from typing import newtype userid = newtype('userid', int) admin_id = userid(1) def get_user_name(user_id: userid) -> str: return f"user_{user_id}" print(get_user_name(admin_id)) # 正确 # print(get_user_name(12345)) # 类型检查器会报错
8. 运行时类型检查
8.1 typeguard
虽然 typing
模块主要用于静态类型检查,但可以与第三方库如 typeguard
结合实现运行时检查:
from typeguard import typechecked from typing import list @typechecked def process_numbers(numbers: list[int]) -> float: return sum(numbers) / len(numbers) print(process_numbers([1, 2, 3])) # 2.0 # process_numbers([1, '2', 3]) # 运行时抛出typeerror
8.2 get_type_hints
from typing import get_type_hints, list, dict def example(a: int, b: str = "default") -> dict[str, list[int]]: return {b: [a]} print(get_type_hints(example)) # 输出: {'a': <class 'int'>, 'b': <class 'str'>, 'return': dict[str, list[int]]}
9. python 3.10+ 新特性
9.1 联合类型语法糖
# python 3.10 之前 from typing import union def old_way(x: union[int, str]) -> union[int, str]: return x # python 3.10+ def new_way(x: int | str) -> int | str: return x
9.2 typeguard
from typing import typeguard, list, union def is_str_list(val: list[union[str, int]]) -> typeguard[list[str]]: return all(isinstance(x, str) for x in val) def process_items(items: list[union[str, int]]) -> none: if is_str_list(items): print("all strings:", [s.upper() for s in items]) else: print("mixed types:", items) process_items(["a", "b", "c"]) # all strings: ['a', 'b', 'c'] process_items([1, "b", 3]) # mixed types: [1, 'b', 3]
10. 迁移策略
10.1 逐步添加类型提示
# 第一阶段:无类型提示 def old_function(x): return x * 2 # 第二阶段:添加简单类型提示 def partially_typed_function(x: int) -> int: return x * 2 # 第三阶段:完整类型提示 from typing import typevar, sequence t = typevar('t') def fully_typed_function(items: sequence[t], multiplier: int) -> list[t]: return [item * multiplier for item in items]
10.2 处理动态类型代码
import types from typing import any, union, cast def dynamic_function(func: union[types.functiontype, types.builtinfunctiontype]) -> any: result = func() # 如果我们知道特定函数的返回类型,可以使用cast if func.__name__ == 'get_answer': return cast(int, result) return result
typing 模块总结
- 为 python 添加静态类型提示支持
- 提供丰富的类型注解工具(
list
,dict
,union
等) - 支持泛型编程(
typevar
,generic
) - 包含高级类型特性(
literal
,typeddict
,protocol
等) - 与 python 3.10+ 的新语法(
|
运算符)良好集成 - 类型提示在运行时几乎没有性能影响,因为它们主要被静态类型检查器使用
typing
模块中的一些特殊形式(如generic
)可能会引入轻微的开销- 在性能关键代码中,考虑使用简单的类型提示或仅在开发时使用类型检查
总结
到此这篇关于python类型系统typing模块示例详解的文章就介绍到这了,更多相关python类型系统typing模块内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论