Disjointness of two types implies that neither is a subtype of the other

发布时间:2026/9/10 18:39:06

Disjointness of two types implies that neither is a subtype of the other Disjointness of two types implies that neither is a subtype of the other【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruffThis is a regression test for https://github.com/astral-sh/ty/issues/2236.[environment] python-version 3.11from types import FunctionType from ty_extensions import Not, AlwaysTruthy, static_assert from ty_extensions._internal import is_subtype_of, is_disjoint_from class Meta(type): ... class F(metaclassMeta): ... static_assert(not is_subtype_of(tuple[FunctionType, type[F]], Not[tuple[*tuple[AlwaysTruthy, ...], Meta]])) static_assert(not is_subtype_of(Not[tuple[*tuple[AlwaysTruthy, ...], Meta]], tuple[FunctionType, type[F]])) static_assert(is_disjoint_from(tuple[FunctionType, type[F]], Not[tuple[*tuple[AlwaysTruthy, ...], Meta]]))这份测试虽短却同时覆盖了 ty 类型系统中的多个关键特性 - [environment] 中的 python-version 3.11变长元组语法 tuple[*tuple[...]] 依赖 PEP 6463.11 引入测试必须在 3.11 环境下运行 - class Meta(type) 与 class F(metaclassMeta)构造一个元类及其使用者用于考验类型检查器对元类关系的推理 - 三个 static_assert分别验证正向非子类型反向非子类型不相交三个结论且三者必须同时成立。 ## 二、三个断言逐一拆解 ### 2.1 测试中的两个复杂类型 先定义两个被比较的类型 python S tuple[FunctionType, type[F]] # 第一个元组类型 T Not[tuple[*tuple[AlwaysTruthy, ...], Meta]] # 第二个是否定类型 - S tuple[FunctionType, type[F]]一个二元组第一元素是任意函数对象FunctionType第二元素是 type[F]——即类对象 F 及其子类对象的类型 - T Not[tuple[*tuple[AlwaysTruthy, ...], Meta]]Not[...] 表示补集见下文 4.3 节被取反的内部类型是 tuple[*tuple[AlwaysTruthy, ...], Meta]——一个以零个或多个 AlwaysTruthy 元素开头、并以一个 Meta 元素收尾的变长元组。 ### 2.2 三条断言的含义 python static_assert(not is_subtype_of(tuple[FunctionType, type[F]], Not[tuple[*tuple[AlwaysTruthy, ...], Meta]])) static_assert(not is_subtype_of(Not[tuple[*tuple[AlwaysTruthy, ...], Meta]], tuple[FunctionType, type[F]])) static_assert(is_disjoint_from(tuple[FunctionType, type[F]], Not[tuple[*tuple[AlwaysTruthy, ...], Meta]])) | 断言 | 表达 | 验证的性质 | | --- | --- | --- | | 第 1 条 | S 不是 T 的子类型 | 不相交 ⇒ S ⊄ T | | 第 2 条 | T 不是 S 的子类型 | 不相交 ⇒ T ⊄ S | | 第 3 条 | S 与 T 不相交 | 两个类型确实无公共居民 | static_assert 是 [crates/ty_python_semantic/resources/mdtest/ty_extensions.md](https://link.gitcode.com/i/bb395401c0b0718becd1ea659d489e6b) 中描述的测试原语它接收任意表达式若表达式在静态层面已知为真则通过否则产生 static-assert-error 诊断。因此前两条断言写成 not is_subtype_of(...)相当于要求子类型判定必须返回否第三条要求不相交判定必须返回是。三者合起来即回归测试标题所述性质**disjointness 蕴含两个方向上的非子类型关系**。 ## 三、核心类型学原理为什么不相交必然互不为子类型 ### 3.1 不相交性的定义 在 ty 的类型系统中两个类型 S 与 T 不相交当且仅当它们的交集为空等价于 Never Two types S and T are disjoint if they have no overlap; that is, their intersection S T is empty (equivalent to Never). 这段定义直接出自 [crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md](https://link.gitcode.com/i/9bf91d1977e570d0ae664a4874ac04f6) 的开篇也是本文回归测试所依赖的公理基础。 ### 3.2 不相交 ⇒ 互不为子类型 该结论可由子类型的定义直接推出 - 若 S ⊆ TS 是 T 的子类型则 S 的所有居民都是 T 的居民S T S 非空 - 若 T ⊆ S同理可得 S T T 非空 - 因此一旦 S T ∅不相交S ⊆ T 与 T ⊆ S 必然都不成立。 回归测试正是针对这一逻辑关系编写只要第 3 条断言不相交成立前两条断言双向非子类型就必须同时成立若类型检查器在子类型或不相交判定上出现偏差测试即失败。issue #2236 即是历史上暴露出的此类判定不一致问题。 ### 3.3 逆命题不成立 需要强调的是该性质是**单向蕴含**不相交一定互不为子类型但互不为子类型并不代表不相交。例如两个独立的普通类 A 与 B无继承关系互不为子类型却可能存在同时继承二者的子类 C因此 A 与 B 并不 disjoint。这一点在 [crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md](https://link.gitcode.com/i/9bf91d1977e570d0ae664a4874ac04f6) 的 Class hierarchies 一节有大量测试佐证 python class A: ... class B1(A): ... class B2(A): ... # B1 和 B2 都是 A 的子类故不与 A disjoint static_assert(not is_disjoint_from(A, B1)) static_assert(not is_disjoint_from(A, B2)) # B1 与 B2 也不 disjoint因为可能存在共同的子类 class C(B1, B2): ... static_assert(is_subtype_of(C, B1 B2)) 只有当类被 final 修饰不可再被继承或元类互不相容时类层次才会产生 disjoint 关系。 ## 四、测试中四个关键类型构造的原理 ### 4.1 FunctionType 与 AlwaysTruthy函数对象恒为真 AlwaysTruthy 与 AlwaysFalsy 是 ty 中描述真值性恒真 / 恒假的特殊类型见 [crates/ty_python_semantic/resources/mdtest/ty_extensions.md](https://link.gitcode.com/i/bb395401c0b0718becd1ea659d489e6b) AlwaysTruthy and AlwaysFalsy represent the sets of all possible objects whose truthiness is always truthy or falsy, respectively. Python 中的函数对象永远为真因此 FunctionType 是 AlwaysTruthy 的子类型。这是回归测试中 S 的第一个元素能够落入被取反元组内部类型的原因之一。 ### 4.2 type[F] 与元类 Meta类对象是其元类的实例 元类是类的类。class F(metaclassMeta) 声明 F 的元类是 Meta意味着类对象 F 本身是 Meta 的一个实例。由于元类会被子类继承type[F]F 及其所有子类的类对象类型中的每个居民也都是 Meta 的实例即 python type[F] 是 Meta 的子类型 这正是回归测试中 S 的第二个元素能够与内部元组类型的收尾元素 Meta 匹配的关键。ty 需要有能力穿透元类 → 实例这层关系来完成子类型判定本测试即是对该能力的回归保护。仓库中 [crates/ty_python_semantic/resources/mdtest/metaclass.md](https://link.gitcode.com/i/bf05ee84bd27a97c9c328ec9b81752b6) 与 [crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md](https://link.gitcode.com/i/9bf91d1977e570d0ae664a4874ac04f6) 的 Instance types versus type[T] types 一节还提供了更多元类参与 disjoint 判定的用例。 ### 4.3 Not[...]否定类型补集 Not[T] 是 ty_extensions 提供的特殊形式表示 T 的补集。之所以需要它是因为 Python 语言本身无法直接表达交集否定等类型层面的运算。仓库中的说明如下 The ty_extensions module provides the Intersection and Not type constructors (special forms) which allow us to construct these types directly. 在该测试中 python T Not[tuple[*tuple[AlwaysTruthy, ...], Meta]] T 就是所有**不**属于 tuple[*tuple[AlwaysTruthy, ...], Meta] 的类型。 ### 4.4 变长元组 tuple[*tuple[AlwaysTruthy, ...], Meta] tuple[*tuple[AlwaysTruthy, ...], Meta] 是 PEP 646 变长元组零个或多个 AlwaysTruthy 元素紧跟着一个 Meta 元素。即它包含 tuple[Meta]、tuple[AlwaysTruthy, Meta]、tuple[AlwaysTruthy, AlwaysTruthy, Meta]……等所有形状。 综合 4.1 与 4.2S tuple[FunctionType, type[F]] 恰好是 (AlwaysTruthy, Meta) 形状因而 python tuple[FunctionType, type[F]] ⊆ tuple[*tuple[AlwaysTruthy, ...], Meta] 即 S 完全落在被取反的内部类型之中。由于 Not[...] 是内部类型的补集S 与 T Not[...] 的交集必然为空——**这就是两条类型 disjoint 的根本原因**也正是第 3 条断言成立的理论依据。 ## 五、底层实现DisjointnessChecker 与 is_disjoint_from ### 5.1 公开 API 层 is_disjoint_from 与 is_subtype_of 定义在 [crates/ty_vendored/ty_extensions/_internal.pyi](https://link.gitcode.com/i/d05e44a6e1cacb6bcb7ec2c3d788aa7f) 中是面向类型系统测试的内部原语 python def is_subtype_of(ty: TypeForm[object], of: TypeForm[object]) - ConstraintSet: Returns a constraint set that is satisfied when ty is a subtype of of. def is_disjoint_from( type_a: TypeForm[object], type_b: TypeForm[object] ) - ConstraintSet: Returns a constraint set that is satisfied when type_a and type_b are disjoint types. Two types are disjoint if they have no inhabitants in common. 二者的返回类型都是 ConstraintSet约束集由 static_assert 求值后产生 Literal[True] / Literal[False]。注释中的 Two types are disjoint if they have no inhabitants in common 与 3.1 节的文档定义完全一致。 ### 5.2 核心判定逻辑 在 [crates/ty_python_semantic/src/types/relation.rs](https://link.gitcode.com/i/42e1608cdf8f64f57a37dde2154c8f59) 中Type 实现了 is_disjoint_from约第 870 行其语义注释揭示了实现思路 Return true if self other should simplify to Never: if the intersection of the two types could never be inhabited by any possible runtime value. Our implementation of disjointness for non-fully-static types only returns true if the *top materialization* of self has no overlap with the *top materialization* of other. For example, list[int] is disjoint from list[str]: the two types have no overlap. But list[Any] is not disjoint from list[str]: there exists a fully static materialization of list[Any] (list[str]) that is a subtype of list[str]. 这里的两个要点 1. **交集简化为 Never**is_disjoint_from 的判定目标就是self other 是否为空与文档定义互为表里 2. **materialization物化策略**对含 Any 等渐进类型gradual type的类型判定只在其顶层物化无交集时才返回真。list[Any] 与 list[str] 不 disjoint因为 list[Any] 存在一个完全静态的物化 list[str] 与后者重叠。 实现上is_disjoint_from 会调用 when_disjoint_from构造一个 DisjointnessChecker 并注入四类访问器visitor - HasRelationToVisitor关系遍历负责子类型等关系 - IsDisjointVisitor不相交性遍历负责具体类型的 disjoint 规则 - SignatureRelationVisitor签名关系遍历 - ApplyTypeMappingVisitor类型物化/映射。 随后调用 checker.check_type_pair(db, self, other) 完成成对检查最后通过 is_always_satisfied 判断约束集是否恒成立。这条调用链正是第 2.2 节三个断言在执行时真正触达的代码路径。 ## 六、元组不相交性规则的完整图景 回归测试中的 S 是一个元组类型而 ty 对元组何时 disjoint有完整的规则体系集中记录在 [crates/ty_python_semantic/resources/mdtest/type_compendium/tuple.md](https://link.gitcode.com/i/535c3d1247920ee767aa3674203941a7) 的 Disjointness 一节 **规则 1最小长度不兼容的元组必 disjoint** Two tuples with incompatible minimum lengths are always disjoint, regardless of their element types. (The lengths are incompatible if the minimum length of one tuple is larger than the maximum length of the other.) python static_assert(is_disjoint_from(tuple[()], tuple[int])) static_assert(not is_disjoint_from(tuple[()], tuple[int, ...])) static_assert(not is_disjoint_from(tuple[str, ...], tuple[int, ...])) **规则 2对应位置元素 disjoint 则元组 disjoint** A tuple that is required to contain elements P1, P2 is disjoint from a tuple that is required to contain elements Q1, Q2 if either P1 is disjoint from Q1 or if P2 is disjoint from Q2. python final class F1: ... final class F2: ... static_assert(is_disjoint_from(tuple[F1, F2], tuple[F2, F1])) static_assert(not is_disjoint_from(tuple[N1, N2], tuple[N2, N1])) **规则 3变长部分永不导致 disjoint** The variable-length portion of a tuple can never cause the tuples to be disjoint, since all variable-length tuple types contain the empty tuple. python static_assert(not is_disjoint_from(tuple[F1, ...], tuple[F2, ...])) **规则 4元组类型不与任意实例类型 disjoint** 由于元组可被子类化ty 刻意放宽了这一判定同时为了自洽禁止两个不同特化的异构元组出现在同一条 MRO 中 python class C: ... static_assert(not is_disjoint_from(tuple[int, str], C)) class I1(tuple[F1, F2]): ... class I2(tuple[F2, F1]): ... class CommonSubtypeOfTuples(I1, I2): ... # error: [invalid-generic-class] 而 [crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md](https://link.gitcode.com/i/9bf91d1977e570d0ae664a4874ac04f6) 的 Tuple types 一节进一步补充了元组与字面量、变长元组之间的 disjoint 用例 python static_assert(is_disjoint_from(tuple[()], TypeOf[object])) static_assert(is_disjoint_from(tuple[None], None)) static_assert(is_disjoint_from(tuple[Literal[1]], tuple[Literal[2]])) static_assert(is_disjoint_from(tuple[Literal[1], Literal[2]], tuple[Literal[1], Literal[3]])) static_assert(not is_disjoint_from(tuple[Literal[1], Literal[2]], tuple[int, ...])) 可以看出本文的回归测试是这条规则链上一个高难度的组合用例它同时混合了元组、否定类型、变长元组、真值性类型与元类专门用于防止某个子规则改动时引入回归。 ## 七、否定类型与交集视角下的 disjoint 从实现角度S 与 Not[U] 的 disjoint 判定等价于检查 S Not[U] ∅。在 [crates/ty_python_semantic/resources/mdtest/type_properties/is_disjoint_from.md](https://link.gitcode.com/i/9bf91d1977e570d0ae664a4874ac04f6) 的 Intersections 一节可以找到同款推理模式的正向与负向用例 python # 一侧是正元素、另一侧是该元素的否定时二者 disjoint static_assert(is_disjoint_from(int, ~int)) static_assert(is_disjoint_from(X ~Literal[1], Literal[1])) # 但父类与子类的否定并不总是 disjoint class Parent: ... class Child(Parent): ... static_assert(not is_disjoint_from(Parent, ~Child)) static_assert(is_disjoint_from(~Parent, Child))【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/10 18:39:06

香农公式通俗推导:从AWGN信道容量到QAM与信号完整性工程实践

1. 先把这个公式抄在纸上:C B log₂(1 S/N) 做通信和电路的人,没有一个不认识香农公式。不管是讨论信道容量、规划调制阶数、评估链路预算,还是分析信号完整性对误码率的影响,最后都会被这句话框住: C B log₂(1 …

2026/9/10 18:39:05

Python日常脚本实战:文件处理、Excel自动化与踩坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 19:29:11

信息技术治理3.1框架:数字化转型中的架构管控实践

1. 项目概述:信息技术治理的日常实践 "每天写点什么"这个系列我已经坚持了三年多,2026年2月5日这篇笔记聚焦的是信息技术治理这个专业领域。作为企业数字化转型的亲历者,我发现很多技术团队在追求创新时常常忽视治理这个基础环节&a…

2026/9/10 19:29:11

A星算法详解:从原理到实战的路径规划指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 19:29:11

6个无需特殊网络的高效宝藏网站推荐

1. 项目概述今天想和大家分享6个我最近发现的宝藏网站,它们不需要任何特殊网络配置就能直接访问,而且功能强大到让人惊叹。作为一名互联网从业者,我经常需要寻找各种工具和资源,这些网站不仅解决了我的实际需求,还带来…

2026/9/10 19:29:11

AI代理上下文生命周期管理:从提示词到可运维软件资产

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/10 19:29:11

JWT认证原理与实战:从Session到Token的演进

1. 为什么我们需要JWT:传统认证的痛点与革新 在Web应用开发中,认证(Authentication)和授权(Authorization)是两个永恒的主题。传统的基于Session的认证机制已经服务了我们很多年,但随着现代应用…

2026/9/10 19:24:11

CANN/ge GE自定义算子架构设计

GE Custom Operator Architecture Design 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提…

2026/9/10 16:39:38

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/10 11:16:38

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 16:31:09

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/10 0:00:55

目录对比去重实战:用哈希算法精准清理重复文件

我电脑里现在还有一块换了三次机的“数据墓地”硬盘,里面存着2016年以前所有旧笔记本的完整备份。平时不觉得有什么,直到前阵子想把它整理归档,发现同一个安装包、同一批照片、同一份论文草稿,在几个不同的备份目录里反复出现。更…

2026/9/10 0:00:55

Leaflet离线地图完整Demo合集:内网部署与坐标纠偏实战

简介:这是一份面向Web GIS开发者的LeafLet离线地图示例合集,帮助开发者快速掌握离线地图从搭建到交互的完整流程。压缩包共723个文件,大小14.06MB,以319个js脚本、175个html页面和29个css样式文件为主体,配合png/svg图…

2026/9/10 0:00:55

MATLAB读取Rinex 3.02观测文件:多系统GNSS数据解析实战

简介:基于MATLAB开发的Rinex3.02版观测文件(o文件)读取代码包,面向卫星定位导航方向的学习者与研究人员,用于解决新版观测文件的数据解析、历元提取与时间转换问题。压缩包共4个文件,包含两个m脚本、一个19…

2026/9/10 12:32:02

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/10 15:19:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/10 15:49:53

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码