[Python] typing 模块 : Python 3 内置模块 [Python 3.5 - ]

概述: typing 模块 (Python 内置模块)

简介

  • Python 的 typing 模块自 Python 3.5 版本引入,为静态类型注解提供了支持。

这个模块主要用于增强代码的可读性和维护性,尽管 Python 是一种动态类型语言类型注解使得开发者能够更清晰地了解函数和变量的预期类型。

类型别名和新类型

  • 类型别名,是使用 type 语句定义的,它创建一个 TypeAliasType 的实例。例如,Vector 和 list[float] 将被静态类型检查器等同处理。类型别名适用于简化复杂的类型签名。NewType 助手则用于创建与原类型不同的新类型,这对于捕捉逻辑错误很有用。

可调用对象的标注

  • 函数或其他可调用对象可以使用 collections.abc.Callabletyping.Callable 来标注。

例如,Callable[[int], str] 表示一个接受 int 类型的单个参数并返回 str 的函数。

泛型(Generic)

  • 泛型,允许通过使用类型形参语法来实现参数化,从而为容器元素添加预期的类型。例如,Sequence[Employee] 表示序列中的所有元素都必须是 Employee 实例。

标注元组

  • 元组在 Python 的类型系统中是特殊情况,可以接受任意数量的类型参数。例如,tuple[int, str] 表示一个长度为 2 的元组,第一个元素是 int,第二个是 str。

类对象的类型

  • 用 C 注解的变量可以接受类型 C 的值。而用类型 type[C] 注解的变量则可以接受 C 的类对象。

用户定义的泛型类型

用户定义的类可以定义为泛型类。例如,LoggedVar[T] 表示类 LoggedVar 是围绕单个类型变量 T 实现参数化的。

Any 类型

  • Any 是一种特殊的类型,表示没有约束的类型。所有类型都与 Any 兼容,反之亦然。

名义子类型 vs 结构子类型

  • Python 静态类型系统最初被定义为使用名义子类型,这意味着类 A 必须是 B 的子类才能使用。PEP 544 允许结构子类型,也称为静态鸭子类型。

模块内容

typing 模块定义了一系列的类、函数和装饰器,如 Any、Union、Tuple、Callable、TypeVar 和 Generic 等。

特殊类型原语

  • typing 模块中的特殊类型原语,如 Any、Union、Optional、Literal、Final 和 TypeAlias,用于在注解中表示类型。

特殊形式

  • typing 模块中的特殊形式,如 Union、Optional、Concatenate 和 Literal,支持下标用法,并具有唯一的语法。

构造泛型类型与类型别名

  • typing.Generic 用于泛型类型的抽象基类,而 typing.TypeVar 和 typing.ParamSpec 用于构造类型变量和形参专属变量。

其他特殊指令

  • typing 模块中的其他特殊指令,如 NamedTuple、NewType、Protocol、runtime_checkable 和 TypedDict,用于创建和声明类型。

类型检查工具

  • 可以使用 mypy 等静态类型检查工具进行类型检查,以确保代码符合类型注解。

注意事项

  • 静态类型检查工具辅助,不会影响 Python 的动态特性,可以选择性地使用类型注解。类型注解应该让代码更易于理解,但不应使代码变得过于复杂。

Union

简介

  • 作用

在 Python 的类型提示(Type Hints)中,Union 是一个非常重要的工具,用于指定一个变量或函数参数可以接受多种类型中的任意一种。
其来自 typing 模块。

Union 的主要作用是允许一个变量或参数具有多种可能的类型,而不是单一的类型。这在实际开发中非常有用,因为某些函数可能需要处理多种类型的输入,而 Union 可以明确地表达这种需求。

  • 使用方法

Union 的语法是 Union[Type1, Type2, ...],其中 Type1Type2 等是可能的类型。
从 Python 3.10 开始,Union 也可以通过 | 操作符来表示,这种方式更简洁。

  • 简答示例
from typing import Union

# 使用 Union 指定变量可以是 int 或 str
def add_or_concatenate(a: Union[int, str], b: Union[int, str]) -> Union[int, str]:
    if isinstance(a, int) and isinstance(b, int):
        return a + b
    elif isinstance(a, str) and isinstance(b, str):
        return a + b
    else:
        raise TypeError("Both arguments must be of the same type: int or str")

# 使用 | 操作符(Python 3.10+)
def add_or_concatenate(a: int | str, b: int | str) -> int | str:
    if isinstance(a, int) and isinstance(b, int):
        return a + b
    elif isinstance(a, str) and isinstance(b, str):
        return a + b
    else:
        raise TypeError("Both arguments must be of the same type: int or str")
  • 优点
  • 类型安全:通过明确指定变量或参数可以接受的类型,可以减少运行时错误。
  • 代码可读性:让代码的意图更加清晰,其他开发者更容易理解函数的输入和输出。
  • 静态类型检查:工具(如 mypy)可以利用这些类型提示进行静态类型检查,提前发现潜在的类型错误。
  • 注意事项
  • 尽量避免过度使用:虽然 Union 提供了灵活性,但过多使用可能会使代码变得复杂。如果可能,尽量将函数或变量的类型限制为单一类型。
  • 兼容性:在 Python 3.10 之前,必须使用 Union,而在 Python 3.10 及以上版本中,可以使用 | 操作符,但需要确保代码的兼容性。

使用场景: 当函数需要接受多种类型的入参/出参或变量时,Union 可明确地表达这一点

  • 使用场景

场景1 - 函数参数:当函数需要接受多种类型的参数时,使用 Union 可以明确地表达这一点。

def process_data(data: Union[int, float, str]) -> None:
    if isinstance(data, int):
        print(f"Processing integer: {data}")
    elif isinstance(data, float):
        print(f"Processing float: {data}")
    elif isinstance(data, str):
        print(f"Processing string: {data}")

场景2 - 返回值:当函数的返回值可能有多种类型时,也可以使用 Union。

def get_value(condition: bool) -> Union[int, str]:
    if condition:
        return 42
    else:
        return "Hello"

场景3 - 变量类型:在定义变量时,也可以使用 Union 来指定变量可以是多种类型。

from typing import Union

value: Union[int, str] = 10
value = "Hello"  # 也可以是字符串

BinaryIO

使用场景: typing.io.BinaryIO(): 打开和读取二进制文件

  • Python中,typing.io.BinaryIO()是一个类型提示函数,它表示二进制输入/输出流

它可以用于函数或方法参数类型注释,以指示预期的输入或输出类型。
这对于静态类型检查和代码文档生成非常有用。

  • 要打开和读取二进制文件,我们可以使用内置的open()函数,并指定打开模式为二进制模式'rb')。
from typing import BinaryIO

def read_binary_file(fileBinBytes: BinaryIO, byteSize: int) -> bytes:	
    data = fileBinBytes.read(byteSize)
    return data

# 打开二进制文件
with open('example.blf', 'rb') as fileBinBytes:
    # 读取文件内容
    binary_data = read_binary_file(fileBinBytes, 10)
    
    # 处理二进制数据
    print(binary_data)
	
	byte_count = len(binary_data)
	print(f"字节数为: {byte_count} bytes")

out

b'LOGG\x90\x00\x00\x00\x947'

分析:

b'LOGG':4 个字节(每个字符占用 1 个字节)
\x90:1 个字节(十六进制表示的字节)
\x00\x00\x00:3 个字节(3 个零字节)
\x94:1 个字节
b'7':1 个字节

案例:读写数据到文件

from typing import BinaryIO

def read_file(file: BinaryIO) -> None:
    # 读取文件内容
    data = file.read()
    # 打印文件内容
    print(data)

def write_file(file: BinaryIO, data: bytes) -> None:
    # 写入数据到文件
    file.write(data)

# 打开二进制文件进行读取
with open('example.bin', 'rb') as file:
    read_file(file)

# 打开二进制文件进行写入
with open('example.bin', 'wb') as file:
    write_file(file, b'Hello, World!')

X 参考文献

https://github.com/python/cpython/tree/3.13/Lib/typing.py

posted @ 2025-06-19 20:45  千千寰宇  阅读(88)  评论(0)    收藏  举报