尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

深入 Ruff Ty 内置作用域解析:条件遮蔽内置名称的语义与 mdtest 测试验证

发布时间:2026/9/11 1:07:36

资讯中心
01
ARTICLE

深入 Ruff Ty 内置作用域解析:条件遮蔽内置名称的语义与 mdtest 测试验证

深入 Ruff Ty 内置作用域解析:条件遮蔽内置名称的语义与 mdtest 测试验证
深入 Ruff Ty 内置作用域解析条件遮蔽内置名称的语义与 mdtest 测试验证【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff在 Python 类型检查中abs、chr、len这类无需导入即可使用的内置名称builtin究竟由谁定义、何时被局部变量或全局变量遮蔽是作用域解析scope resolution中最容易出错的环节之一。本文以 Ruff 仓库中 ty 类型检查器的测试文档 crates/ty_python_semantic/resources/mdtest/scopes/builtin.md 为主体结合 作用域解析源码 与 内置符号查找实现完整讲解条件遮蔽内置名称的两类场景函数局部遮蔽与全局遮蔽下名称解析与类型推断的精确语义并说明如何读懂、运行这些 Markdown 驱动的类型检查测试。内置作用域Builtin Scope在 ty 中的定位Python 的名称解析遵循局部 → 闭包外层 → 全局模块→ 内置的层级顺序。内建命名空间builtins是最后一级回退当一个名字在模块级也找不到时类型检查器才需要决定它是否真的是一个内置名称。在 ty 类型检查器中这一回退逻辑集中在两个关键位置crates/ty_python_semantic/src/types/definition_resolution.rs#L152-L180 中的definitions_for_name先在当前作用域及其可见祖先作用域中查找绑定与声明只有全部落空时才调用implicit_builtins_symbol_scope回退到隐式内置crates/ty_python_semantic/src/place.rs#L637-L716 中的builtins_symbol_impl实现了内置名称的实际解析路径——优先在项目级__builtins__模块中查找找不到再回退到标准库 typeshed 的builtins模块即KnownModule::Builtins。值得注意的细节是ty 对内置设置了BuiltinVisibility::RuntimeOnly可见性过滤place.rs#L695-L701只有运行时确实存在的符号才可作为隐式内置名称解析那些仅在类型检查期存在如 typeshed 中纯 typing 辅助符号的名字不会泄漏成隐式内置。理解了这条最后一级回退链路后下面两个测试用例就非常值得深入它们检验的正是当内置名称被条件性遮蔽时这条回退链路该如何被打破或保留。场景一函数局部条件遮蔽内置名称builtin.md 中的第一个测试Conditional local override of builtin验证如果一个内置名称在函数内被局部变量条件性遮蔽该函数的绑定作用域将终止名称解析——此时名字可能处于未绑定unbound状态但绝不会回退到内置名称def _(flag: bool) - None: if flag: abs 1 chr: int 1 # error: [possibly-unresolved-reference] reveal_type(abs) # revealed: Literal[1] # error: [possibly-unresolved-reference] reveal_type(chr) # revealed: Literal[1]逐行解读这个测试if flag:分支内对abs赋值、对chr做注解声明chr: int 1。由于flag类型是bool分支可能走也可能不走因此abs、chr在函数作用域内是条件绑定执行到reveal_type那一行时它们可能已绑定为1也可能完全未绑定。关键语义一旦某个作用域中存在对名字的绑定哪怕是条件绑定名称解析就不会再越过该作用域回退到内置作用域。所以abs和chr不可能解析为内置的abs/chr函数。因为可能未绑定ty 发出possibly-unresolved-reference诊断# error:断言但一旦绑定发生类型就是Literal[1]因此revealed:为Literal[1]chr虽然声明为int但绑定值是字面量1窄化为Literal[1]。这里的# error: [possibly-unresolved-reference]对应仓库中的规则文档 crates/ty_python_semantic/resources/lint_docs/possibly-unresolved-reference.md它检查对可能未定义名称的引用因为运行时使用未定义变量会抛出NameError。该规则当前默认关闭原因是误报数量较多——这也解释了为什么测试中要显式写出错误断言而不是依赖规则默认开启。场景二全局条件遮蔽内置名称第二个测试Conditionally global override of builtin验证的是对称场景如果内置名称被模块级全局变量条件性遮蔽那么名称查找应当把内置类型与条件定义的类型做联合uniondef flag() - bool: return True if flag(): abs 1 chr: int 1 def _(): # TODO: Should ideally be Literal[1] | (def abs(x: SupportsAbs[_T], /) - _T) reveal_type(abs) # revealed: Literal[1] # TODO: Should ideally be int | (def chr(i: SupportsIndex, /) - str) reveal_type(chr) # revealed: int与场景一的本质区别在于遮蔽发生的层级场景一是函数局部遮蔽绑定作用域函数作用域终止了解析内置名称彻底不可见场景二是模块级全局遮蔽。函数_内部读取abs时其作用域内没有绑定名称解析会上升到模块作用域发现abs被条件绑定为1同时由于该绑定是条件性的模块作用域的查找结果可能未定义因此不会直接切断对内置作用域的回退理论结果应当是两种可能性的联合。文档中的TODO注释精确给出了 ty 自己认可的理想类型abs理想应为Literal[1] | (def abs(x: SupportsAbs[_T], /) - _T)即条件绑定的字面量 1与内置abs函数签名的联合chr理想应为int | (def chr(i: SupportsIndex, /) - str)即声明为 int 的条件绑定与内置chr函数签名的联合。而当前实现给出的实际结果Literal[1]与int尚未把内置函数签名并入联合——这是实现层面的已知差距TODO而不是语义设计意图。文章在此不做已完成的断言仅说明当前仓库实际输出的revealed类型。这两个用例恰好形成一组互补的契约局部条件遮蔽 → 终结内置回退只报 possibly-unresolved全局条件遮蔽 → 保留内置回退理论 union当前仅输出条件定义类型。读懂断言mdtest 的# revealed:与# error:语法builtin.md 属于 ty 的 Markdown 测试体系mdtest。该体系的完整规范见 crates/ty_test/README.md其核心规则是每个 Markdown 文件是一个测试套件#标题用于切分独立的测试builtin.md中的两个 H2 标题即为两个独立测试每个测试由 fenced 的py或pyi、ipynb代码块构成运行时会写入内存文件系统并执行一次完整类型检查# revealed: X必须紧邻一次reveal_type(...)调用断言该表达式被推断出的类型显示形式与X完全一致# error: [rule-code]断言该行上会产生一条对应规则码rule code的诊断规则码断言是测试类型检查器语义时的首选写法断言可以叠加、可以指定列号如# error: 8 [rule-code]具体解析逻辑见 crates/mdtest/src/assertion.rs。reveal_type是类型检查器的约定内置即使没有显式from typing import reveal_type检查器也会假装它是内置方便测试直接调用crates/ty_test/README.md#L60-L62。builtin.md 的两个用例都没有导入reveal_type正是利用了这一便利。底层原理为什么局部与全局条件遮蔽行为不同结合源码可以进一步解释两个场景差异的实现来源作用域内存在绑定即停止上溯。definition_resolution.rs 的scoped_definitions_for_name从当前作用域向上遍历祖先作用域一旦在某层作用域找到定义就break不再继续向上——包括不再进入内置回退。场景一正是函数作用域找到了条件定义于是终结解析因此内置回退被阻断产生possibly-unresolved-reference。未找到定义才回退内置。只有scoped_definitions_for_name返回空集时definitions_for_name才走implicit_builtins_symbol_scope → definitions_for_builtin链路。场景二中函数_自身没有绑定模块作用域的条件绑定属于可能未定义名字解析会带着可能未绑定的标记继续回退从而在理论上与内置类型做联合。内置符号解析的模块顺序。builtins_symbol_implplace.rs#L669-L716先尝试项目级__builtins__模块再尝试标准 typeshedbuiltins模块并使用RuntimeOnly可见性过滤 typing-only 符号。仓库中还有一组单元测试印证了内置名称解析不会触发作用域推断这一性能相关设计builtin_names_do_not_infer_scope测试definition_resolution.rs#L861-L884验证对isinstance、float、complex等名字做定义解析时不会触发infer_scope_types_impl查询避免形成推断循环。与相邻作用域测试的对照builtin 作用域的行为并不是孤立的它与其他作用域规则共享条件绑定这一核心机制。同目录下的两个测试文件提供了很好的对照scopes/unbound.mdUnbound function local 用例展示函数作用域内只要有定义即使未绑定就不会回退到全局而 global.md 中条件性全局重绑后嵌套作用域仍可见原模块级绑定如reveal_type(value) # revealed: Literal[updated, 0]则说明条件绑定会与原有绑定做联合——这与 builtin.md 场景二条件全局遮蔽应 union 内置类型的设计意图完全一致只是当前对 builtin 的 union 尚未完整实现。这些测试共同刻画了 ty 的一个统一原则无条件绑定遮蔽外层定义条件绑定则把可能的外层定义/内置定义并入联合同时标记 possibly-unresolved。运行与验证这些测试builtin.md 中的测试由 crates/ty_python_semantic/tests/mdtest.rs 集成测试驱动它把 resources/mdtest 目录下所有.md文件都注册为测试套件resources/README.md 说明了这一约定。在仓库根目录运行# 运行全部 Markdown 驱动测试 cargo test -p ty_python_semantic -- mdtest # 只运行 scopes 相关测试 cargo test -p ty_python_semantic -- mdtest__scopes # 带 MDTEST_TEST_FILTER 精确过滤某个测试 MDTEST_TEST_FILTERConditional local override of builtin \ cargo test -p ty_python_semantic --test mdtest也推荐使用仓库自带的 watch 模式运行器crates/ty_python_semantic/mdtest.py它会在 Markdown 文件变更时自动重跑对应测试、在 Rust 代码变更时自动重新编译uv run crates/ty_python_semantic/mdtest.py scopes/builtin.md需要说明的是运行测试仅涉及查看与执行仓库本身是只读的不应在生成过程中修改任何文件。小结通过 builtin.md 这组 mdtest 用例可以精确掌握 ty 类型检查器对内置作用域的建模内置名称解析是名称查找的最后一级回退由definitions_for_name→implicit_builtins_symbol_scope链路实现优先项目级__builtins__再回退标准 builtins函数局部条件遮蔽会终止内置回退读取点为 possibly-unresolved绑定后类型按实际值推断模块级条件遮蔽设计上应与内置类型 union文档 TODO 给出了理想类型当前实现仅输出条件定义侧类型属于已知的未完成项上述语义均由# revealed:与# error:断言以可执行测试的形式固化任何改动都会在cargo test中被即时检验。对于想为 ty 或类似 Rust 类型检查器贡献作用域语义的开发者builtin.md 及其相邻的 global.md、unbound.md、nonlocal.md 是一组高密度、可直接运行验证的语义规范。【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。