Python类型系统typing模块示例详解

Written by

in

文章目录
  • typing 模块在 Python 3.5 中引入,用于支持类型提示(Type Hints)。它提供了: 用于类型注释的工具 泛型类型支持 类型别名 回调协议 以及其他高级类型系统特性
  • Annotated 是 Python typing 模块中一个强大但常被忽视的类型注解工具,它允许我们在类型提示中添加额外的元数据。这个功能在 Python 3.9 中引入,为类型系统提供了更大的灵活性。Annotated 的基本形式如下: from typing import Annotated Annotated[<type>, <metadata1>, <metadata2>, …] 其中: <type> 是基础类型 <metadata> 可以是任意对象,提供额外的类型信息
  • 为 Python 添加静态类型提示支持 提供丰富的类型注解工具(List, Dict, Union 等) 支持泛型编程(TypeVar, Generic) 包含高级类型特性(Literal, TypedDict, Protocol 等) 与 Python 3.10+ 的新语法(| 运算符)良好集成 类型提示在运行时几乎没有性能影响,因为它们主要被静态类型检查器使用 typing 模块中的一些特殊形式(如 Generic)可能会引入轻微的开销 在性能关键代码中,考虑使用简单的类型提示或仅在开发时使用类型检查
  • 到此这篇关于Python类型系统typing模块示例详解的文章就介绍到这了,更多相关Python类型系统typing模块内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Python中typing模块与类型注解的使用方法 一篇文章带你了解python中的typing模块和类型注解 Python 中的 typing 模块常见用法 Python中typing模块的具体使用 Python类型注解必备利器typing模块全面解读 python typing模块–类型提示支持 使用Python Typing模块提升代码可读性和健壮性实例探索
  • 目录
    • 1. 模块概述
    • 2. 基础类型提示
      • 2.1 基本类型注释
      • 2.2 类型别名
    • 3. 复合类型
      • 3.1 Union 类型
      • 3.2 Optional 类型
      • 3.3 Any 类型
    • 4. 泛型类型
      • 4.1 TypeVar
      • 4.2 Generic 类
    • 5. 函数类型
      • 5.1 Callable
      • 5.2 可调用对象协议
    • 6. 带元数据的类型Annotated
      • 6.1 基本示例
      • 6.2 核心特性
      • 6.3 应用场景
      • 6.4 与其他类型工具结合
      • 6.5 运行时访问元数据
      • 6.6. 实际案例:数据库字段类型
    • 7. 高级类型特性
      • 7.1 Literal 类型
      • 7.2 TypedDict
      • 7.3 NewType
    • 8. 运行时类型检查
      • 8.1 typeguard
      • 8.2 get_type_hints
    • 9. Python 3.10+ 新特性
      • 9.1 联合类型语法糖
      • 9.2 TypeGuard
    • 10. 迁移策略
      • 10.1 逐步添加类型提示
      • 10.2 处理动态类型代码
    • typing 模块总结
      • 总结 

        typing 模块在 Python 3.5 中引入,用于支持类型提示(Type Hints)。它提供了:

        • 用于类型注释的工具
        • 泛型类型支持
        • 类型别名
        • 回调协议
        • 以及其他高级类型系统特性

        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]
        

        from typing import List, Tuple
        
        # 创建类型别名
        Vector = List[float]
        Point = Tuple[float, float]
        
        def scale_vector(v: Vector, factor: float) -&gt; Vector:
            return [x * factor for x in v]
        
        def distance(p1: Point, p2: Point) -&gt; float:
            return ((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)**0.5
        

        • 表示属于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
        

        • 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
        

        • 表示可以使用任何类型,不建议常用
        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
        

        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
        

        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
        

        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
        

        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
        

        Annotated 是 Python typing 模块中一个强大但常被忽视的类型注解工具,它允许我们在类型提示中添加额外的元数据。这个功能在 Python 3.9 中引入,为类型系统提供了更大的灵活性。Annotated 的基本形式如下:

        from typing import Annotated
        
        Annotated[<type>, <metadata1>, <metadata2>, ...]
        

        其中:

        • <type> 是基础类型
        • <metadata> 可以是任意对象,提供额外的类型信息

        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
        

        • 保留类型信息

        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
        

        • 数据验证

        结合 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}")
        

        • 与 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")  # 类型检查器会报错
        

        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')
        

        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 的类型系统提供了强大的扩展能力,使得类型提示不仅可以用于静态检查,还能携带丰富的运行时信息,为框架开发和复杂系统设计提供了更多可能性。

        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")  # 类型检查器会报错
        

        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"}
        

        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))        # 类型检查器会报错
        

        虽然 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
        

        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]]}
        

        # 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
        

        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]
        

        # 第一阶段:无类型提示
        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]
        

        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
        

        • 为 Python 添加静态类型提示支持
        • 提供丰富的类型注解工具(ListDictUnion 等)
        • 支持泛型编程(TypeVarGeneric
        • 包含高级类型特性(LiteralTypedDictProtocol 等)
        • 与 Python 3.10+ 的新语法(| 运算符)良好集成
        • 类型提示在运行时几乎没有性能影响,因为它们主要被静态类型检查器使用
        • typing 模块中的一些特殊形式(如 Generic)可能会引入轻微的开销
        • 在性能关键代码中,考虑使用简单的类型提示或仅在开发时使用类型检查

        到此这篇关于Python类型系统typing模块示例详解的文章就介绍到这了,更多相关Python类型系统typing模块内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

        您可能感兴趣的文章:

        • Python中typing模块与类型注解的使用方法
        • 一篇文章带你了解python中的typing模块和类型注解
        • Python 中的 typing 模块常见用法
        • Python中typing模块的具体使用
        • Python类型注解必备利器typing模块全面解读
        • python typing模块–类型提示支持
        • 使用Python Typing模块提升代码可读性和健壮性实例探索

        站内搜索