Ruff ty 类型检查器诊断消息中的同名类型消歧全限定名Fully Qualified Name机制详解【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff本文围绕 Ruff 仓库内 ty 类型检查器ty_python_semanticcrate的核心诊断机制展开当一次诊断中同时出现多个同名类型例如两个模块各自定义class DataFrame时ty 通过打印全限定名称fully qualified name来区分它们避免用户被含混的类型名误导。文章完整继承同名消歧在类、枚举、Protocol、TypedDict、泛型别名、可调用特殊形式、方法/构造器、联合类型、类型断言、继承与元类冲突等场景下的全部测试用例并结合源码display.rs 中的AmbiguousNameCollector与AmbiguityState讲解其底层判定逻辑。读者读完可掌握 ty 诊断信息中限定名的生成规则、两级消歧策略模块名 → 文件行号以及如何阅读并复用 same_names.md 这类 mdtest 文档验证类型检查器行为。背景为什么诊断信息需要全限定名Python 代码中同名类型极其常见两个第三方库都可能定义DataFrame、Config或Model同一个包内不同子模块也可能各自定义同名类。当类型检查器type checker报告一条invalid-assignment赋值不兼容、invalid-argument-type实参类型错误或unresolved-attribute属性不存在诊断时如果仅仅写出DataFrame用户根本无法判断到底是哪一个。ty 的解决方案写在文档开篇第一句ty prints the fully qualified name to disambiguate objects with the same name.即在一条诊断消息里如果同时出现了多个同名但不同的类型ty 会为它们补全所属模块乃至外层类、函数、来源文件与行号使每个类型名都能被唯一识别。反之当同一诊断上下文中不存在同名竞争类型时ty 会保持简洁、只显示未限定的短名详见下文方法与构造器描述一节对Other.method的说明。这一行为不是临时拼凑的字符串处理而是由类型显示子系统type display subsystem统一负责。核心实现位于 crates/ty_python_semantic/src/types/display.rs。限定名生成与两级消歧的源码原理在深入各个场景前先理解实现机制。display.rs中有一个名为AmbiguousNameCollector的收集器它遍历一条诊断涉及的所有类型按**短名unqualified name**分组记录每个命名项类ClassLiteral或类型别名TypeAliasType见源码中NamedItem枚举并维护每个名字当前的歧义状态Unambiguous首次遇到尚无竞争用短名即可RequiresFullyQualifiedName遇到了限定路径不同的同名项此时必须用全限定名区分如a.DataFramevsb.DataFrameRequiresFileAndLineNumber连全限定名都相同例如同一模块内两个分支各自声明的Model此时必须再追加文件路径 行号 列号才能区分。对应源码display.rs中的QualificationLevel枚举只有两个取值ModuleName与FileAndLineNumberAmbiguityState::from_ambiguity_state负责将歧义状态映射到这两种限定级别。收集完成后DisplaySettings会把限定级别表qualified/qualified_type_aliases注入格式化过程随后的Display实现据此决定每个类型名输出时是否带上前缀。限定名的路径组件由 display.rs 的qualified_name_components_from_scope计算它沿作用域链向上遍历把外层类名、外层函数格式化为locals of function f、以及模块名依次收集并反转排序例如类D位于a.b模块的类C的方法m内部时组件为[a, b, C, locals of function m]。该逻辑同时被QualifiedClassNameclass.rs与类型别名的限定名实现共享。需要强调两点设计细节类与类型别名共用同一张限定名表。注释明确指出一个类和一个类型别名同名时也需要被区分因此DisplaySettings的qualified与qualified_type_aliases共享同一个qualification_mapdisplay.rs。FileAndLineNumber级别的后缀形如 src/package/foo.py:1:7即来源文件 行号 列号见 display.rs 的定位逻辑且一旦追加该后缀输出文本就不再是合法的 Python 类型表达式is_valid_syntax置为false因为其中包含文件路径等非语法成分。本文档的载体mdtest 测试框架同一名字的消歧 本身是一个mdtest测试套件——Ruff 用 Markdown 编写类型检查/类型推断测试。根据 crates/ty_test/README.md 的说明任何 Markdown 文件都可以成为测试套件其中每个py/pyi围栏代码块被写成一个内存文件默认路径/src/mdtest_snippet.py框架运行类型检查后把诊断与测试内嵌的# error:断言逐一匹配。断言语法有三种粒度# error: [invalid-assignment]要求命中该行的诊断规则代码为invalid-assignment# error: Object of type ...要求诊断完整消息包含引号内的文本# error: 8 [rule-code]/# error: 8 text额外要求诊断文本跨度起始于该行第 8 列1 起始。部分用例还使用snapshot围栏块给出完整快照式输出含行号、下划线标注与info:附加说明。测试入口注册在 crates/ty_python_semantic/tests/mdtest.rsdatatest_stable::harness!将./resources/mdtest下所有.md文件作为测试也就是说本文档中的每一行示例都是可运行的回归测试。类class场景下的同名消歧嵌套类Nested class同一模块内两个外层类各自定义同名嵌套类B时仅写B无法区分ty 输出外层类全名class A: class B: pass class C: class B: pass a: A.B C.B() # error: [invalid-assignment] Object of type test.C.B is not assignable to test.A.B这里test.C.B与test.A.B展示了模块名 外层类名 类名的完整限定格式诊断同时涉及A.B与C.B两个同名类故二者都必须被限定test.为当前测试模块名。函数内的嵌套类Nested class in function当同名类遮蔽发生在函数作用域内时限定名会携带locals of function f路径组件对应qualified_name_components_from_scope对ScopeKind::Function的处理class B: pass def f(b: B): class B: pass # error: [invalid-assignment] Object of type test.locals of function f.B is not assignable to test.B b B()函数f内的局部类B显示为test.locals of function f.B而模块级B保持test.B两者一望即知分别属于哪个作用域。来自不同模块的同名类Class from different modules两个模块a.py、b.py各自定义DataFrame混用时若只写DataFrame必然产生歧义import a import b df: a.DataFrame b.DataFrame() # error: [invalid-assignment] Object of type b.DataFrame is not assignable to a.DataFrame def _(dfs: list[b.DataFrame]): # error: [invalid-assignment] Object of type list[b.DataFrame] is not assignable to list[a.DataFrame] dataframes: list[a.DataFrame] dfsa.py与b.py内容均为class DataFrame: pass注意第二个用例限定名穿透了容器类型list[...]list[b.DataFrame]与list[a.DataFrame]内部元素被逐一限定说明AmbiguousNameCollector会递归遍历类型结构如泛型参数收集所有嵌套出现的同名项。可变参数注解Variadic parameter annotations*args/**kwargs这类可变参数的注解在类型系统中会被展开为容器类型元组 / 字典因此相关的赋值诊断同样需要限定名来区分容器元素。可变位置参数Variadic positional parameterfirst.py与second.py各定义class Value: ...函数将*values: first.Value重新赋值为second.Value的元组import first import second def assign(*values: first.Value) - None: values (second.Value(),) # snapshot: invalid-assignmenterror[invalid-assignment]: Object of type tuple[second.Value] is not assignable to tuple[first.Value, ...] -- src/mdtest_snippet.py:5:14 | 4 | def assign(*values: first.Value) - None: | ----------- Variadic parameter annotation declares the type as tuple[first.Value, ...] 5 | values (second.Value(),) # snapshot: invalid-assignment | ^^^^^^^^^^^^^^^^^ Incompatible value of type tuple[second.Value]快照中附带一条定位到注解的辅助标注Variadic parameter annotation declares the type astuple[first.Value, ...]可变位置参数注解声明类型为tuple[first.Value, ...]使*values的真实底层类型一目了然。可变关键字参数Variadic keyword parameter对应**values的底层类型是dict[str, ...]import first import second def assign(**values: first.Value) - None: values {item: second.Value()} # snapshot: invalid-assignmenterror[invalid-assignment]: Object of type dict[str, first.Value | second.Value] is not assignable to dict[str, first.Value] -- src/mdtest_snippet.py:5:14 | 4 | def assign(**values: first.Value) - None: | ----------- Keyword-variadic parameter annotation declares the type as dict[str, first.Value] 5 | values {item: second.Value()} # snapshot: invalid-assignment | ^^^^^^^^^^^^^^^^^^^^^^^^ Incompatible value of type dict[str, first.Value | second.Value] info: element second.Value of union first.Value | second.Value is not assignable to first.Value这条快照还有一个值得注意的细节因为字典的值类型被推断为联合类型first.Value | second.Valueinfo:附加说明逐元素指出联合中的second.Value不可赋值给first.Value——联合成员的限定名在这里再次发挥了区分作用。歧义声明来源Ambiguous declaration origins当同一变量在多个分支if/else中反复声明、且类型相同时ty 仍能把声明侧类型与赋值侧类型区分开import first import second def assign(flag: bool) - None: if flag: value: first.Value else: value: first.Value value second.Value() # snapshot: invalid-assignmenterror[invalid-assignment]: Object of type second.Value is not assignable to first.Value -- src/mdtest_snippet.py:10:13 | 10 | value second.Value() # snapshot: invalid-assignment | ----- ^^^^^^^^^^^^^^ Incompatible value of type second.Value | | | Declared type first.Value即便两个分支声明的是同一个first.Value诊断依然给出声明的类型是first.ValueDeclared type的辅助说明并与右侧的second.Value形成对照避免用户误以为变量声明类型含糊不清。同限定名的终极兜底文件与行号前面提到当两个同名项连限定路径都相同时AmbiguityState会升级为RequiresFileAndLineNumber。本节的用例展示了这一升级同一个包内foo.py与foo.pyi类型存根文件分别定义MyClass二者的限定名都是package.foo.MyClass此时必须追加来源位置package/__init__.pyfrom .foo import MyClass def make_MyClass() - MyClass: return MyClass()package/foo.pyiclass MyClass: ...package/foo.pyclass MyClass: ... def get_MyClass() - MyClass: from . import make_MyClass # error: [invalid-return-type] Return type does not match returned value: expected package.foo.MyClass src/package/foo.py:1:7, found package.foo.MyClass src/package/foo.pyi:1:7 return make_MyClass()两条同名类分别来自.py与.pyi实现/存根仅凭package.foo.MyClass依然无法区分因此 ty 追加了 src/package/foo.py:1:7与 src/package/foo.pyi:1:7形式的文件:行:列后缀——这正是QualificationLevel::FileAndLineNumber与RequiresFileAndLineNumber状态在诊断输出中的直接体现。枚举Enum相关场景不同模块的同名枚举status_a.py与status_b.py各自定义class Status(Enum)成员值类型不同一个为int、一个为str跨模块混用枚举成员时import status_a import status_b # error: [invalid-assignment] Object of type Literal[status_b.Status.ACTIVE] is not assignable to status_a.Status s: status_a.Status status_b.Status.ACTIVE枚举成员被表示为字面量类型Literal[status_b.Status.ACTIVE]其所属枚举类带上了模块前缀。嵌套枚举Nested enum与嵌套类同理不同外层类内的同名嵌套枚举也需要限定from enum import Enum class A: class B(Enum): ACTIVE active INACTIVE inactive class C: class B(Enum): ACTIVE active INACTIVE inactive # error: [invalid-assignment] Object of type Literal[test.C.B.ACTIVE] is not assignable to test.A.B a: A.B C.B.ACTIVE类对象Class literals与泛型别名类字面量Class literals当被赋值的对象是类本身而非实例时类型显示为class cls_b.Config与type[cls_a.Config]import cls_a import cls_b # error: [invalid-assignment] Object of type class cls_b.Config is not assignable to type[cls_a.Config] config_class: type[cls_a.Config] cls_b.Configcls_a.py、cls_b.py各自定义class Config: pass。泛型别名Generic aliases对带类型参数的类做下标访问Container[int]后整体赋值时限定名穿透类型实参import generic_a import generic_b # error: [invalid-assignment] Object of type class generic_b.Container[int] is not assignable to type[generic_a.Container[int]] container: type[generic_a.Container[int]] generic_b.Container[int]generic_a.py/generic_b.py各自定义from typing import Generic, TypeVar T TypeVar(T) class Container(Generic[T]): passProtocol协议成员不同的同名 Protocolbad.py定义了成员名拼写错误__nexxt__的Iterator与typing.Iterator同名。在main.py中混用时返回类型诊断给出完整限定名bad.pyfrom typing import Protocol, TypeVar T_co TypeVar(T_co, covariantTrue) class Iterator(Protocol[T_co]): def __nexxt__(self) - T_co: ... def bad() - Iterator[str]: raise NotImplementedErrormain.pyfrom typing import Iterator def f() - Iterator[str]: import bad # error: [invalid-return-type] Return type does not match returned value: expected typing.Iterator[str], found bad.Iterator[str] return bad.bad()注意typing.Iterator[str]与bad.Iterator[str]并排出现前者来自标准库typing模块后者来自本地bad模块。成员相同但类型不同的 Protocol两个协议类proto_a.Drawable与proto_b.Drawable成员相同都有draw方法但返回类型不同Nonevsint。仅凭结构上看它们并不兼容诊断需要模块前缀from typing import Protocol import proto_a import proto_b def _(drawable_b: proto_b.Drawable): # error: [invalid-assignment] Object of type proto_b.Drawable is not assignable to proto_a.Drawable drawable: proto_a.Drawable drawable_bproto_a.pyfrom typing import Protocol class Drawable(Protocol): def draw(self) - None: ...proto_b.pyfrom typing import Protocol class Drawable(Protocol): def draw(self) - int: ...TypedDict两个模块分别定义dict_a.Person与dict_b.Personname字段类型分别为str与bytes赋值诊断from typing import TypedDict import dict_a import dict_b def _(b_person: dict_b.Person): # error: [invalid-assignment] Object of type dict_b.Person is not assignable to dict_a.Person person_var: dict_a.Person b_persondict_a.py/dict_b.py各自定义from typing import TypedDict class Person(TypedDict): name: str # 或 bytes元组特化Tuple specializations即使两个同名类一个在module.py、一个在测试模块自身mdtest_snippet诊断也会分别限定class Model: ... def get_models_tuple() - tuple[Model]: from module import Model # error: [invalid-return-type] Return type does not match returned value: expected tuple[mdtest_snippet.Model], found tuple[module.Model] return (Model(),)module.py内容为class Model: ...。这里测试模块自身也被命名为mdtest_snippet并出现在限定名中说明 ty 对当前模块同样按全限定名处理。可调用特殊形式Callable special forms两个Callable[...]签名中各自嵌套了同名类StartResponsety 仍能区分first.pyfrom typing import Callable class StartResponse: ... Application Callable[[StartResponse], int]测试片段模拟导入失败时的回退声明from typing import Callable try: from first import Application, StartResponse except ImportError: class StartResponse: ... # error: [invalid-assignment] Object of type Callable special-form (mdtest_snippet.StartResponse, /) - int is not assignable to Callable special-form (first.StartResponse, /) - int Application Callable[[StartResponse], int]可调用特殊形式的显示格式为Callable special-form (参数, /) - 返回其中参数位置的同名类分别限定为mdtest_snippet.StartResponse与first.StartResponse。文档注释点明ty 会区分两个可调用特殊形式签名中嵌套的同名类。方法、构造器与内置类的描述方法与构造器描述Method and constructor descriptionsty 能把绑定方法 / 未绑定方法 / 构造器所属的定义类与同名参数类型区分开而当诊断中不存在可见歧义时方法所有者保持未限定unqualified。first.pyclass Model: ...second.pyimport first class Model: def __init__(self, value: first.Model) - None: ... def method(self, value: first.Model) - None: ... class Other: def method(self, value: first.Model) - None: ...测试片段import second def calls(value: second.Model, other: second.Other) - None: # error: [invalid-argument-type] Argument to bound method second.Model.method is incorrect: Expected first.Model, found Literal[1] value.method(1) # error: [invalid-argument-type] Argument to function second.Model.method is incorrect: Expected first.Model, found Literal[1] second.Model.method(value, 1) # error: [invalid-argument-type] Argument to second.Model.__init__ is incorrect: Expected first.Model, found Literal[1] second.Model(1) # No competing type named Other appears in this diagnostic, so its method owner stays unqualified. # error: [invalid-argument-type] Argument to bound method Other.method is incorrect: Expected Model, found Literal[1] other.method(1)四行调用分别演示绑定方法调用、以类身份直接调用方法显示为function、构造器调用显示second.Model.__init__、以及无竞争时保持简短的Other.method/Model。注意最后一行ExpectedModel 中的Model未带前缀——因为该诊断里唯一的Model就是first.Model不存在需要区分的同名项符合无歧义即不加限定的设计原则。内置类描述Builtin class descriptions当用户定义的类遮蔽了内置类名时ty 会把被调用的内置类与同名实参类型区分开import builtins class tuple: ... def convert(value: tuple) - None: # error: [invalid-argument-type] Argument to class builtins.tuple is incorrect: Expected Iterable[Unknown], found mdtest_snippet.tuple builtins.tuple(value)这里builtins.tuple是真正被调用的内置类而mdtest_snippet.tuple是用户定义的同名类作为实参传入两者在一条诊断中清晰分立。联合类型Union中的成员消歧识别联合成员Identifying union members当联合类型中的某个成员缺少属性时ty 对缺失成员使用的限定名与完整联合保持一致first.pyclass Model: present: intsecond.pyclass Model: ...import first import second def missing_attribute(value: first.Model | second.Model) - int: # error: [unresolved-attribute] Attribute present is not defined on second.Model in union first.Model | second.Model return value.presentsecond.Model没有present属性诊断在联合first.Model | second.Model的上下文中明确指出缺失者是谁。别名化联合成员Aliased union members当联合通过 PEP 695 类型别名type Model ...引入、且别名本身与某个成员同名时ty 依然能区分联合别名与缺属性的成员。first.pyclass Present: present: intsecond.pyclass Model: ...alias.pyimport first import second type Model first.Present | second.Modelfrom alias import Model def missing_attribute(value: Model) - int: # error: [unresolved-attribute] Attribute present is not defined on second.Model in union alias.Model return value.present注意这里测试通过[environment]表指定了python-version 3.12PEP 695 类型别名语法要求 Python 3.12[environment] python-version 3.12alias.Model是整个联合的显示名second.Model则是联合内缺属性的那个成员。同一模块内重定义的联合成员Redefined union members当同一模块内两个分支各定义一个同名类、且二者同时出现在联合里时仅靠模块名已无法区分需要来源位置def coinflip() - bool: return True if coinflip(): class Model: present: int else: class Model: ... # error: [unresolved-attribute] Attribute present is not defined on test.Model src/test.py:9:11 in union test.Model src/test.py:5:11 | test.Model src/test.py:9:11 Model().present联合的两个成员都叫test.Model因此分别追加了 src/test.py:5:11第一个声明处与 src/test.py:9:11第二个声明处。这是文件 行号消歧级别的典型示例AmbiguityState从RequiresFullyQualifiedName升级为RequiresFileAndLineNumber的判定在这里得到完整验证。赋值场景属性与下标属性赋值Attribute assignments普通属性赋值与联合属性赋值中被赋值的类与诊断中其他位置的同名类都会被区分first.py/second.py各自定义class Model: ...import first import second class Owner: item: first.Model class Other: item: int def assign_attribute(owner: Owner, value: second.Model) - None: # error: [invalid-assignment] Object of type second.Model is not assignable to attribute item of type first.Model owner.item value def assign_union_attribute(owner: first.Model | Other, value: second.Model) - None: # error: [invalid-assignment] Object of type second.Model is not assignable to attribute item on type first.Model | Other owner.item value第二条诊断的目标类型是联合first.Model | Other因为Other也有item字段赋值须对所有成员都合法first.Model与second.Model依然被清晰限定。下标赋值Subscript assignments对容器做下标赋值时ty 既会区分被赋值的值与下标键也会区分它们与容器元素类型中嵌套的同名类import first import second def assign_value(values: list[first.Model], value: second.Model) - None: # error: [invalid-assignment] Invalid subscript assignment with key of type Literal[0] and value of type second.Model on object of type list[first.Model] values[0] value def assign_key(values: dict[first.Model, int], key: second.Model) - None: # error: [invalid-assignment] Invalid subscript assignment with key of type second.Model and value of type Literal[1] on object of type dict[first.Model, int] values[key] 1第一条键Literal[0]合法、值second.Model不兼容于list[first.Model]第二条键second.Model不兼容于dict[first.Model, int]的键类型。两条诊断都完整报告键类型 值类型 容器类型三要素。类型断言Type assertions基础断言失败Type assertionsassert_type断言失败时断言的目标类型与被推断类型会分别限定环境为 Python 3.11[environment] python-version 3.11first.py/second.py各定义class Model: ...from typing import assert_type import first import second def invalid_assertion(value: second.Model) - None: assert_type(value, first.Model) # snapshot: type-assertion-failureerror[type-assertion-failure]: Argument does not have asserted type first.Model -- src/mdtest_snippet.py:7:5 | 7 | assert_type(value, first.Model) # snapshot: type-assertion-failure | ^^^^^^^^^^^^-----^^^^^^^^^^^^^^ | | | Inferred type is second.Model info: first.Model and second.Model are not equivalent typesinfo:行明确写出first.Model与second.Model不等价。不可拼写的子类型断言Unspellable subtype assertionsisinstance收窄后产生的交叉类型intersection在 Python 语法中不可拼写unspellable此时 ty 会在整个断言相关类型中维持同名类的区分[environment] python-version 3.11from typing import assert_type import first import second def invalid_subtype_assertion(value: first.Model) - None: if isinstance(value, second.Model): assert_type(value, second.Model) # snapshot: assert-type-unspellable-subtypeerror[assert-type-unspellable-subtype]: Argument does not have asserted type second.Model -- src/mdtest_snippet.py:8:9 | 8 | assert_type(value, second.Model) # snapshot: assert-type-unspellable-subtype | ^^^^^^^^^^^^-----^^^^^^^^^^^^^^^ | | | Inferred type is first.Model second.Model info: first.Model second.Model is a subtype of second.Model, but they are not equivalent推断出的交叉类型first.Model second.Model是second.Model的子类型但不等价因此assert_type报错——尽管该交叉类型本身无法用 Python 语法书写ty 仍以形式展示并用限定名标识其两个组成部分。继承与元类冲突不兼容的继承方法Incompatible inherited methods多个基类提供了不兼容的同名方法时诊断需要指出是哪两个基类的方法冲突。由于派生类与被比较的方法类同名限定名在此同样关键first.pyclass Model: def method(self, value: int) - int: return valuesecond.pyclass Different: def method(self, value: str) - str: return valueimport first import second # error: [invalid-method-override] Base classes for class mdtest_snippet.Model define method method incompatibly: first.Model.method is incompatible with Different.method class Model(first.Model, second.Different): ...派生类mdtest_snippet.Model与基类first.Model同名诊断分别以first.Model.method与Different.method指出两个冲突方法——Different.method之所以不加模块前缀是因为Different未与其他同名项竞争。冲突的元类Conflicting metaclassesconflicting-metaclass诊断会完整区分同名类和同名元类first.pyclass Meta(type): ... class Model(metaclassMeta): ...import first class OtherMeta(type): ... # error: [conflicting-metaclass] derived class (mdtest_snippet.Model) must be a subclass of the metaclasses of all its bases, but OtherMeta (metaclass of mdtest_snippet.Model) and Meta (metaclass of base class first.Model) have no subclass relationship class Model(first.Model, metaclassOtherMeta): ... class Meta(type): ... # error: [conflicting-metaclass] derived class (Other) must be a subclass of the metaclasses of all its bases, but mdtest_snippet.Meta (metaclass of Other) and first.Meta (metaclass of base class Model) have no subclass relationship class Other(first.Model, metaclassMeta): ...第二条诊断中当前模块内的Meta与first.py中的Meta限定为mdtest_snippet.Meta与first.Meta——同名元类在一条消息里被完整区分。小结ty 同名消歧的设计要点纵观全部场景可以归纳出 ty 诊断中同名类型消歧的几条稳定规则按需限定只有当同一条诊断中同时出现同名且不同的类型时才进行限定没有竞争时保持短名见Other.method与Different.method用例。两级递进限定级别从模块名a.DataFrame到文件 行号 列号test.Model src/test.py:5:11后者用于限定路径完全相同如.py与.pyi并存、同一模块内重复声明的极端情形对应 display.rs 中AmbiguityState的三态转换。递归覆盖限定名会穿透容器与泛型list[...]、tuple[...]、dict[...]、Callable[...]、联合与交叉类型对其中嵌套的每个同名类单独判定。类与别名同表类与类型别名共享同一套限定名判定源码NamedItem枚举与共享qualification_map保证同名类/别名在错误消息中被一致区分。来源可追踪locals of function f这类路径组件与 file:line:column后缀直接取自语义索引semantic index与文件定位系统用户可据此在源码中精确定位每一个出现歧义的类型定义。这套机制的价值在于诊断消息既是给开发者看的可读文本也是类型检查器自身行为的可验证规范——same_names.md 中的每一段代码与断言都可以通过cargo test经由 mdtest.rs 注册的 mdtest harness直接回归执行为理解 Ruff 的 ty 类型检查器在真实混淆场景下的表现提供了最直接的观察窗口。【免费下载链接】ruffAn extremely fast Python linter and code formatter, written in Rust.项目地址: https://gitcode.com/GitHub_Trending/ru/ruff创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
