当前位置: 首页 > news >正文

Python类型推导协议

===============================================================================
Python 类型推导与协议 (Protocol & TypeGuard)
===============================================================================
深入 Python 的类型系统:Protocol 实现结构子类型(鸭子类型),
TypeGuard 自定义类型收窄,@runtime_checkable 运行时检查,
以及协变/逆变、类型桩文件等高级主题。
===============================================================================

from typing import (
Protocol, TypeVar, runtime_checkable,
TypeGuard, assert_type, reveal_type,
Iterator, Iterable, overload
)
from typing import TYPE_CHECKING

T = TypeVar("T")

# ===================================================================
# 第一部分:Protocol 结构子类型
# ===================================================================

# -------------------------------------------------------------------
# 1. 基本 Protocol:定义行为接口而非类层次
# -------------------------------------------------------------------
class 可打印(Protocol):
"""任何具有 .to_str() 方法的对象都自动满足此协议"""
def to_str(self) -> str: ...

class 用户:
def __init__(self, name: str):
self.name = name
def to_str(self) -> str:
return f"用户: {self.name}"

class 商品:
def __init__(self, title: str, price: float):
self.title = title
self.price = price
def to_str(self) -> str:
return f"{self.title} (¥{self.price})"

def 格式化输出(对象: 可打印) -> None:
"""接受任何满足 可打印 协议的对象"""
print(f"格式化: {对象.to_str()}")

格式化输出(用户("张三")) # → 格式化: 用户: 张三
格式化输出(商品("Python教程", 39.9)) # → 格式化: Python教程 (¥39.9)

# -------------------------------------------------------------------
# 2. 多方法协议:定义完整接口
# -------------------------------------------------------------------
class 可迭代集合(Iterable[T], Protocol[T]):
"""协议可以继承其他协议或类型"""
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[T]: ...

def 获取大小(集合: 可迭代集合) -> int:
return len(集合)

print(f"列表大小: {获取大小([1, 2, 3])}") # → 3
print(f"集合大小: {获取大小({1, 2, 3, 4})}") # → 4

# -------------------------------------------------------------------
# 3. @runtime_checkable:运行时协议检查
# -------------------------------------------------------------------
@runtime_checkable
class 可序列化(Protocol):
def 序列化(self) -> bytes: ...
def 反序列化(self, 数据: bytes) -> None: ...

class JSON文档:
def 序列化(self) -> bytes:
return b'{"key": "value"}'
def 反序列化(self, 数据: bytes) -> None:
print(f"反序列化: {数据}")

class XML文档:
def 序列化(self) -> bytes:
return b"value"
def 反序列化(self, 数据: bytes) -> None:
print(f"解析 XML: {数据}")

def 保存文档(文档: 可序列化) -> None:
if isinstance(文档, 可序列化):
数据 = 文档.序列化()
print(f"保存 {len(数据)} 字节")
else:
raise TypeError("对象不可序列化")

保存文档(JSON文档()) # → 保存 16 字节

# ===================================================================
# 第二部分:TypeGuard 类型守卫
# ===================================================================

# -------------------------------------------------------------------
# 4. TypeGuard:自定义类型收窄
# -------------------------------------------------------------------
def 是字符串列表(值: list[object]) -> TypeGuard[list[str]]:
"""TypeGuard 让类型检查器知道:如果返回 True,参数就是 list[str]"""
return all(isinstance(x, str) for x in 值)

def 是整数列表(值: list[object]) -> TypeGuard[list[int]]:
return all(isinstance(x, int) for x in 值)

def 处理混合列表(列表: list[object]) -> None:
if 是字符串列表(列表):
print(f"字符串列表: {', '.join(列表)}")
elif 是整数列表(列表):
总和 = sum(列表)
print(f"整数列表, 总和: {总和}")
else:
print(f"混合类型列表: {列表}")

处理混合列表(["a", "b", "c"]) # → 字符串列表: a, b, c
处理混合列表([1, 2, 3, 4, 5]) # → 整数列表, 总和: 15
处理混合列表([1, "two", 3]) # → 混合类型列表

# -------------------------------------------------------------------
# 5. TypeGuard 在类方法中的使用
# -------------------------------------------------------------------
class 数据处理器:
@staticmethod
def 是有效记录(数据: dict[str, object]) -> TypeGuard[dict[str, str | int]]:
return (
"id" in 数据 and isinstance(数据["id"], int)
and "name" in 数据 and isinstance(数据["name"], str)
)
@classmethod
def 处理(cls, 数据: dict[str, object]) -> None:
if cls.是有效记录(数据):
print(f"处理记录: id={数据['id']}, name={数据['name']}")
else:
print("无效记录")

数据处理器.处理({"id": 1, "name": "张三"})

# ===================================================================
# 第三部分:类型推断辅助工具
# ===================================================================

# -------------------------------------------------------------------
# 6. assert_type 和 reveal_type
# -------------------------------------------------------------------
def 类型检查辅助():
值1: int = 42
# reveal_type(值1) # mypy 显示: Revealed type is 'builtins.str'
print(f"类型检查辅助工具: assert_type / reveal_type")

类型检查辅助()

# -------------------------------------------------------------------
# 7. 类型桩文件 (.pyi)
# -------------------------------------------------------------------
def 桩文件示例():
"""
类型桩文件 (.pyi) 为纯 Python 项目提供类型信息:
- 放在与 .py 文件同目录下,文件名相同,扩展名为 .pyi
- 只包含类型签名,不含实现
"""
print("类型桩文件 (.pyi) 为已有模块添加类型信息")
print("优点:不改动源码即可添加类型")

桩文件示例()

# ===================================================================
# 第四部分:协变与逆变在 Protocol 中的应用
# ===================================================================

# -------------------------------------------------------------------
# 8. Protocol 中的协变与逆变
# -------------------------------------------------------------------
T_co = TypeVar("T_co", covariant=True)
T_con = TypeVar("T_con", contravariant=True)

class 生产者(Protocol[T_co]):
"""协变协议:只产生(返回)值"""
def 获取(self) -> T_co: ...

class 消费者(Protocol[T_con]):
"""逆变协议:只消费(接收)值"""
def 放入(self, 值: T_con) -> None: ...

class Int生产者:
def 获取(self) -> int:
return 42

def 使用生产者(p: 生产者[float]) -> None:
print(f"生产值: {p.获取()}")

使用生产者(Int生产者()) # 协变允许

class Float消费者:
def 放入(self, 值: float) -> None:
print(f"消费浮点: {值}")

def 需要int消费者(c: 消费者[int]) -> None:
c.放入(100)

需要int消费者(Float消费者()) # 逆变允许

# ===================================================================
# 第五部分:综合应用示例
# ===================================================================

# -------------------------------------------------------------------
# 9. 完整的 Protocol 实战:仓库模式
# -------------------------------------------------------------------
T实体 = TypeVar("T实体")

class 仓库(Protocol[T实体]):
def 按ID获取(self, id: int) -> T实体 | None: ...
def 保存(self, 实体: T实体) -> None: ...
def 删除(self, id: int) -> bool: ...

@runtime_checkable
class 可验证(Protocol):
def 验证(self) -> bool: ...

class 用户仓库:
def __init__(self):
self._数据: dict[int, str] = {}
def 按ID获取(self, id: int) -> str | None:
return self._数据.get(id)
def 保存(self, 实体: str) -> None:
id = hash(实体) % 10000
self._数据[id] = 实体
def 删除(self, id: int) -> bool:
return self._数据.pop(id, None) is not None
def 验证(self) -> bool:
return len(self._数据) < 1000

def 执行仓库操作(仓库对象: 仓库[str]) -> None:
仓库对象.保存("测试数据")
if isinstance(仓库对象, 可验证):
print(f"验证通过: {仓库对象.验证()}")

u = 用户仓库()
执行仓库操作(u)

# ===================================================================
# 总结
# ===================================================================
# Python 类型推导与协议核心概念:
#
# Protocol:
# - 结构子类型:根据对象的方法签名判断类型(鸭子类型)
# - @runtime_checkable: 支持 isinstance() 运行时检查
# - 可继承其他协议/类型组合接口
#
# TypeGuard:
# - 自定义类型收窄函数
# - 类型检查器根据返回值收窄类型
#
# 辅助工具:
# - assert_type: 运行时断言类型(开发调试)
# - reveal_type: 让类型检查器显示推断类型
# - .pyi 桩文件: 为已有模块添加类型信息
#
# 协变/逆变:
# - 协变 (covariant): 生产者/只读容器
# - 逆变 (contravariant): 消费者/只写容器
# - 不变 (invariant): 读写兼备的容器

http://www.gsyq.cn/news/1429843.html

相关文章:

  • 城通网盘解析器:3分钟掌握免费高速下载的终极方案
  • OpencvSharp 算子学习教案之 - Cv2.CvtColor
  • MATLAB图论实战:除了shortestpath,自己写的Dijkstra函数如何优化与可视化?
  • 3PEAK思瑞浦 TP5551-TR SOT23-5 精密运放
  • OmenSuperHub:彻底释放惠普暗影精灵游戏本性能的终极解决方案
  • OpencvSharp 算子学习教案之 - Cv2.CvtColorTwoPlane
  • 双系统Ubuntu18.04升级22.04,安装docker进行openclaw安装
  • 【电赛保姆级教程】别在比赛时从零写代码了!电赛“祖传代码库”搭建与OLED多级菜单硬核指南
  • 2026年5月AI模型性能排行:代码能力Claude霸榜,智谱GLM杀入前十
  • 调试记录 - 2024年1月15日
  • 告别排版焦虑:西安交大LaTeX论文模板让你专注学术创新
  • 【电赛保姆级教程】别再用L298N了!电赛电机驱动与高阶控制(带FOC扫盲)硬核避坑指南
  • LabVIEW与外部设备通信秘籍:用DLL传递复杂结构体(含数组/嵌套结构)的完整配置流程
  • 那些年,我追Google Trends追到精疲力尽的故事
  • 深入FIO引擎:除了libaio,这些ioengine(如sync, psync, mmap)在Linux下到底怎么选?性能差多少?
  • 口袋神器!Arduino 创客必备,可接入 DeepSeek、Qwen 等 AI 大模型,通过 GPIO 串口控制 IoT 智能设备
  • C# 泛型
  • C++之父开撕AI Coding:资深开发者宁愿退休也不愿伺候AI生成的代码
  • 为什么你的论文参考文献格式总是不对?3个GB/T 7714 BibTeX样式终极解决方案
  • 187、运动控制中的行业应用:机械臂力控打磨
  • 前端内存泄漏常见场景与排查
  • GTA5线上小助手:免费开源工具帮你轻松称霸洛圣都终极指南
  • Kettle官网大变样?别慌!手把手教你找到最新9.3版本的下载入口(附Hadoop Shims获取指南)
  • 【AI+房地产实战指南】:2024年最值得落地的7大智能整合场景与避坑清单
  • ARP 协议:网络世界里的“地址翻译官“
  • SBM-20-1盖革管3D打印端盖制作:从零打造专业级辐射探测器接口
  • 2026AI漫剧创作深度测评:如何为你的创作需求匹配最佳方案? - 速递信息
  • 189、运动控制中的行业应用:医疗设备(手术机器人)
  • 英雄联盟R3nzSkin换肤工具实战指南:国服安全自定义皮肤完整方案
  • yuzu模拟器架构深度解析:从Switch硬件仿真到跨平台渲染优化