当前位置: 首页 > 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.jsqmd.com/news/918524/

相关文章:

  • DeepSeek V1
  • [智能体-128]:智能体,模型与工具的整合者
  • OpenAI GPT-5 Agent Mode 正式发布:最长24小时自主任务,AI编程智能体大战升级
  • 城通网盘解析器:3分钟掌握免费高速下载的终极方案
  • TrafficMonitor插件完全指南:打造你的个性化桌面监控中心
  • OpencvSharp 算子学习教案之 - Cv2.CvtColor
  • MATLAB图论实战:除了shortestpath,自己写的Dijkstra函数如何优化与可视化?
  • 基于知识图谱与专家系统的散热材料智能推荐技术
  • 3PEAK思瑞浦 TP5551-TR SOT23-5 精密运放
  • OmenSuperHub:彻底释放惠普暗影精灵游戏本性能的终极解决方案
  • 智能体协同下的数字孪生IOC:端流融合与场景编排的工程选型逻辑
  • 双系统Ubuntu18.04升级22.04,安装docker进行openclaw安装
  • OpencvSharp 算子学习教案之 - Cv2.CvtColorTwoPlane
  • 如何高效解密网易云音乐NCM文件:ncmdumpGUI完整技术解析与实战指南
  • 避坑指南:在LabVIEW 2023中设计波形发生器UI时,如何优雅管理控件状态与数据流?
  • 【电赛保姆级教程】别在比赛时从零写代码了!电赛“祖传代码库”搭建与OLED多级菜单硬核指南
  • 用Java+SpringBoot给服务器告警邮件找个‘飞书管家’:保姆级配置教程(附避坑点)
  • Debian 11 Bullseye 新装后必做的 10 件事:从内核 5.10 到 LibreOffice 7.0 的实用调优
  • 量子计算中的测量基优化与误差缓解技术
  • 26年AI漫剧制作厂商排行榜多家深度格局解析 - 速递信息
  • 河北君宏泵业:排污泵/循环泵/隔膜泵/消防泵/混流泵专业制造与多场景应用 - 品牌推荐官
  • 调试记录 - 2024年1月15日
  • BioAge终极指南:5步掌握生物年龄计算与衰老评估的R语言工具包
  • bugkuctf-web-文件上传(kali操作)
  • Mac重装系统卡在“最后1秒”?别慌,这可能是APFS格式和安装时间预估的锅
  • 新 E 选品牌源头厂家无溶剂 PU 烤火罩耐刮耐磨吗
  • 2026年5月AI模型性能排行:代码能力Claude霸榜,智谱GLM杀入前十
  • 实习19-HRM
  • 告别排版焦虑:西安交大LaTeX论文模板让你专注学术创新
  • 【电赛保姆级教程】别再用L298N了!电赛电机驱动与高阶控制(带FOC扫盲)硬核避坑指南