Basilisk退出Python类型检查排行榜:typing生态加速规范收敛
2026/8/30 13:41:28 网站建设 项目流程

如果你一直在关注 Python 的类型检查生态,最近应该注意到一个不大但很有意思的消息:Basilisk 已经从 Python typing conformance leaderboard 中被移除了。

这个事件,单看似乎只是某个小众工具的下架,但在 Python typing 生态正在快速走向“规范收敛”的当下,它传递的信号远比新闻本身重要。

这篇文章不想只复述一条动态。我会先解释 Basilisk 是什么、conformance leaderboard 在测什么、为什么会有工具被移除,再进一步分析:作为普通 Python 开发者,这件事对你选择类型检查工具、编写类型注解、排查 ImportError 错误,到底有没有实际影响。最后会给出可落地的自查方法和工程建议。

无论你是刚接触 Python typing 的新手,还是在团队里推广类型检查的工程负责人,这篇文章都值得读完并收藏备用。

1. 这件事真正要解决的问题

先说结论:Basilisk 被移除,不等于 Basilisk 项目死亡,也不代表它“一无是处”。更合理的理解是——Python typing 生态正在从“百花齐放”走向“标准收敛”,而 conformance leaderboard 就是这个收敛过程的裁判席。

为什么这件事值得关注?因为对于绝大多数 Python 开发者来说,类型检查工具的选择已经从一个“可选项”变成了“工程必选项”。尤其在 PyCharm、VSCode Pylance、mypy、Pyright 等工具已经深度融入日常开发的今天,了解这些工具背后的评测机制,能帮你回答几个非常现实的问题:

  • 我的代码用哪个类型检查器最稳?
  • 为什么同一个注解,在这台机器上没问题,在另一台机器上就报ImportError
  • 当工具说“支持 typing 规范”时,它到底支持到什么程度?
  • 如果某个工具退出评测,我项目里的代码会不会受影响?

这篇文章要解决的就是这些问题。我会从事件本身出发,把 Basilisk 的设计理念、conformance leaderboard 的评测机制、以及开发者如何应对“工具变动”这三件事讲清楚。

2. Basilisk 是什么:一个不走寻常路的类型检查器

要理解 Basilisk 被移除的意义,得先知道 Basilisk 是什么。

Basilisk 是一个 Python 类型检查器,但它的设计理念和 mypy、Pyright 有本质区别。主流类型检查器大多基于静态分析:直接扫描源码、解析 AST(抽象语法树)、按照类型规则推断每个变量和函数的类型。静态分析的优点是快、不执行代码,缺点是遇到动态特性(比如eval、动态属性、运行时生成的类)时容易出现漏判或误判。

Basilisk 的思路反向而来:它不直接静态分析你的代码,而是先运行代码,捕获运行时暴露出的 Python API 接口信息,再把这些信息转换成类型检查的依据。

用一句话概括:别人的类型检查是“读源码猜类型”,Basilisk 是“跑一遍看类型”。

这种设计有几个明显优势:

  • 对动态特性的容忍度高。只要代码能在运行时跑通,Basilisk 就能捕获到真实的接口签名。
  • 学习成本低。它不需要开发者额外维护复杂的类型标注,甚至可以从无注解代码开始逐步引入类型。
  • 和 Python 运行时结合紧密。它依赖的不是纯文本层面的推断,而是运行时对象信息。

但“运行代码再检查”也有天然短板:它要求代码能真正执行起来。如果项目的某段代码依赖外部服务、数据库、GUI 环境,或者导入时就报错,Basilisk 就很难完整覆盖。这也是它在部分评测场景中表现受限的原因之一。

特性BasiliskmypyPyright
检查方式运行时 API 探索静态分析 AST静态分析 + 类型推断
对动态特性支持较好一般一般
是否需要执行代码
上手成本较低中等
适合场景遗留动态代码逐步引入类型严格类型约束项目大型项目 + IDE 集成

从材料看,Basilisk 被移出 conformance leaderboard 的公告并没有给出复杂的解释,但更稳妥的判断是:这个决定和 Basilisk 的“非主流”设计有关——leaderboard 更看重对 typing 规范本身的符合度,而 Basilisk 的目标更多是运行时的实用覆盖,两者在评测中出现了目标错位。

3. Python typing conformance leaderboard 到底在测什么

先说一个最容易误会的点:conformance leaderboard 不是“工具性能排行榜”,也不是“哪个检查器运行更快”的比赛。它评测的核心是:各个类型检查器对 Python typing 规范(PEP 系列)的符合程度。

Python 的类型注解体系不是一蹴而就的。从 PEP 484(类型注解)、PEP 526(变量注解)、PEP 544(协议)、PEP 586(字面量类型)、PEP 589(TypedDict)、PEP 591(Final)、PEP 604(联合类型写法)、PEP 655(Required/NotRequired)到 PEP 695(泛型新语法),Python 逐年扩展着类型系统的能力边界。

这些 PEP 定义的是“标准”。但标准写出来是一回事,检查器能不能按标准实现是另一回事。conformance leaderboard 就充当了这个“监考老师”:它准备了一批覆盖各类 typing 特性的测试用例,然后逐个检查每个类型检查器能否正确识别、推断和校验这些用例。

评测一般会覆盖这些维度:

  • 基础类型:intstrList[int]Dict[str, int]等。
  • 泛型:Generic[T]TypeVar的约束与协变逆变。
  • 协议:Protocol与结构化子类型。
  • TypedDict:字典键的类型约束,以及Required/NotRequired等修饰。
  • 重载:@overload的匹配逻辑。
  • 类型窄化:isinstanceTypeGuardcast的使用。
  • 字面量类型与 Final。
  • 新语法兼容性:如X | Ytype语句。

如果你的代码天天都在用List[int]Optional[str],你可能觉得这些测试“很简单”。但真正实现一个类型检查器,让它在各种组合场景下都给出符合规范的结论,难度非常高。这也是为什么市面上成熟的检查器屈指可数。

用一张表概括当前常用的类型检查器与规范符合度特点:

检查器主要维护方规范符合度表现集成方式
mypy社区驱动传统、覆盖广、更新稳健命令行、pre-commit、mypy daemon
PyrightMicrosoft覆盖高、速度较快Pylance(VSCode)、命令行、node 环境
pytypeGoogle覆盖动态特性较好命令行、与 Bazel 集成
pyreMeta性能强、适合大型代码库命令行、watchman 集成
Basilisk独立开发者偏离规范细节较多、退出评测独立运行

从这张表可以看出,Basilisk 更接近“探索型”工具:它的价值未必在所有场景都能发挥,但它的设计思路为社区提供了不同方向的参考。

4. Basilisk 被移除这件事,意味着什么

回到事件本身。Basilisk 从 leaderboard 被移除,我认为至少可以从三个层面解读。

4.1 对 Basilisk 项目本身的直接信号

leaderboard 的移除,本质上是一个“资格声明”:在既定评测标准下,Basilisk 已经没有继续参与排名的必要,或者它主动选择了退出。这并不等同于项目的技术失败。更合理的理解是:Basilisk 的项目目标和 leaderboard 的目标不一致。

leaderboard 想要的,是尽可能严格地遵循 PEP 规范;Basilisk 想要的,是用运行时 API 信息来辅助现实项目落地类型检查。当两者目标不一致时,继续保留在榜单上反而会产生误导——读者可能以为它在“规范符合度”上和其他工具同台竞技,但其实它走的是另一条路。

4.2 对 Python typing 生态的行业信号

Basilisk 被移除,更值得留意的信号是:Python typing 生态正在从“工具功能竞争”过渡到“规范符合度竞争”。

几年前,各类型检查器的差异主要在于“你能检查多少种特性”。现在,随着 PEP 规范体系逐步稳定,工具的竞争点开始转向“谁能更准确地实现规范”。这种变化的结果是:对普通开发者而言,不同检查器之间的“方言差异”会越来越小,代码迁移成本也会随之降低。

反过来看,这也意味着那些“规范符合度不够”的工具,如果不调整方向,就会逐渐被主流生态边缘化。Basilisk 不是第一个,也不会是最后一个。

4.3 对开发者的实际影响

从短期看,Basilisk 被移除不会影响你的日常开发。mypy 和 Pyright 依然是主流选择,Pylance 依然在 VSCode 里为你提供智能提示。

但从长期看,这件事提醒我们:不要把项目“焊死”在某一个类型检查工具上。工具会变,排行榜会变,但代码质量的标准不会变。你的代码应该尽量遵循 typing 规范本身,而不是迎合某个检查器的偏好。

5. 类型检查工具格局:从功能竞争到规范收敛

理解趋势之后,我们再回头看看当前 Python 类型检查的格局。为什么 mypy、Pyright 能成为主流,而 Basilisk 这样的探索型工具只能待在角落?

5.1 mypy:传统但可靠

mypy 是最早被广泛接受的 Python 类型检查器,诞生于 2012 年左右。它的优势是“老”:文档多、踩坑经验多、和 Django、SQLAlchemy 等框架的适配方案都齐全。劣势是速度偏慢,特别是在大型项目上。

5.2 Pyright / Pylance:IDE 时代的最佳拍档

Pyright 由微软维护,采用 TypeScript 编写,速度远超 mypy。它内置在 VSCode 的 Pylance 扩展中,开箱即用,几乎零配置。对于新项目,我通常会推荐从 Pyright 入手。

5.3 pytype / pyre:大厂内部工具的开源版本

Google 的 pytype 和 Meta 的 pyre 都偏向大型代码库,强调推断能力强、支持增量检查。它们的设计目标更多是“内部工程效率”,对普通中小项目的体验不一定比 Pyright 更好。

5.4 规范收敛对选型的影响

当所有主流工具都在向同一套 PEP 规范靠拢时,选型逻辑会变得更简单:

  • 团队成员都在用 VSCode,优先 Pyright/Pylance。
  • 团队有严格的 CI 流程和 pre-commit 习惯,mypy 更稳妥。
  • 代码库非常庞大、动态特性多,可以考虑 pytype。
  • 完全依赖运行时信息、想低成本引入类型的探索型项目,Basilisk 的思路仍有参考价值。

真正稳定的判断是:工具可以换,但你对 typing 规范的理解必须扎实。只要代码符合规范,任何检查器都能用;如果代码只针对某个检查器的“偏好”去写,那换工具就有风险。

6. 对普通开发者的实际影响:一个真实的 ImportError 案例

接下来这部分,我们落到代码层面。

记得热搜词里有这样一条错误信息:ImportError: cannot import name 'NotRequired' from 'typing'。这个错误在 Python 版本升级时非常典型,也和 typing 规范收敛直接相关。

NotRequired是 PEP 655 引入的 TypedDict 修饰符。它表示某个字典键“不是必需的”,即实例化 TypedDict 时可以不传这个键。但问题在于:只有 Python 3.11 及以上的版本,NotRequired才被正式收录进标准库typing

如果你的开发环境是 Python 3.10 或更早版本,直接写:

from typing import NotRequired

就会得到开头的ImportError

正确做法有两种:

# 方案一:使用 typing_extensions,兼容旧版本 from typing_extensions import NotRequired, TypedDict
# 方案二:仅限 Python 3.11+ from typing import NotRequired, TypedDict

为什么会发生这种错误?因为 typing 生态的规范是逐年演进的,标准库的更新速度快于很多人的 Python 版本升级速度。你的工具链都在“规范收敛”的路上,但你的运行环境可能还没跟上。

这个例子很好地说明了:使用 typing 特性前,先确认 Python 版本支持范围,而不是默认某个注解写法在所有环境都能运行。用错版本导致 ImportError,往往会被误判为“代码问题”或“环境坏了”,实际只是版本不一致。

7. 自查代码兼容性:从最小示例开始

7.1 先做一个最小项目

假设我们要检查一段代码在不同类型检查器下的表现。创建以下目录结构:

typing_compat_check/ ├── app.py ├── pyproject.toml └── requirements-dev.txt

app.py的内容如下:

# 文件路径:typing_compat_check/app.py from typing import TypedDict class UserProfile(TypedDict): name: str age: int email: str | None def get_user_display_name(user: UserProfile) -> str: return user["name"].title()

这段代码用到了两个特性:

  • TypedDict:从 PEP 589 开始支持。
  • str | None:PEP 604 联合类型写法,Python 3.10 之后可用。

7.2 安装多个检查器进行对比

创建requirements-dev.txt

mypy>=1.0 pyright>=1.1.300 typing_extensions>=4.8.0

安装依赖:

pip install -r requirements-dev.txt

如果安装较慢,可以分别安装单独的工具,例如:

pip install mypy pyright typing_extensions

7.3 运行 mypy

mypy app.py

预期输出(如果一切正常):

Success: no issues found in 1 source file

7.4 运行 Pyright

Pyright 是通过 npm 分发的,但pip install pyright也能安装一个较新的二进制版本。运行方式:

pyright app.py

预期输出:

0 errors, 0 warnings, 1 file

7.5 故意引入兼容性错误,观察报错差异

app.py改成一个“旧版本不兼容”的版本:

# 文件路径:typing_compat_check/app_bad.py from typing import NotRequired, TypedDict class UserProfile(TypedDict): name: str age: int email: NotRequired[str] def get_user_age(user: UserProfile) -> int: return user["age"] * 2

在 Python 3.10 或更低版本中,运行:

python app_bad.py

会得到:

ImportError: cannot import name 'NotRequired' from 'typing'

而运行 mypy:

mypy app_bad.py

如果 mypy 版本较新,并且你设置了python_version = "3.10",它可能会正常通过,因为 mypy 自己实现了NotRequired的语义检查,不依赖运行时环境中的typing模块。这恰恰体现了“类型检查器的规范实现”和“运行时的 typing 模块版本”不是一回事。

正确的修复方式,是把导入改为typing_extensions

# 文件路径:typing_compat_check/app_fixed.py from typing_extensions import NotRequired, TypedDict class UserProfile(TypedDict): name: str age: int email: NotRequired[str] def get_user_age(user: UserProfile) -> int: return user["age"] * 2

再次运行:

python app_fixed.py

你会看到程序正常结束,没有任何错误。

7.6 通过 pyproject.toml 固定检查器配置

推荐在项目根目录配置pyproject.toml,明确工具的运行目标和 Python 版本:

[tool.mypy] python_version = "3.10" strict = true warn_return_any = true warn_unused_configs = true [tool.pyright] pythonVersion = "3.10" typeCheckingMode = "strict" reportMissingTypeStubs = false

这段配置的作用是:无论你本地 Python 是什么版本,类型检查器都会按 3.10 标准来评估代码,避免“本机能过、CI 过不了”的尴尬。

8. 常见问题与排查思路

在实际使用 typing 和类型检查器的过程中,很多报错其实和工具本身无关,而是版本、配置或导入方式的问题。下面整理几张排查清单。

8.1 ImportError 类问题

问题现象可能原因排查方式解决方案
cannot import name 'NotRequired' from 'typing'Python 版本低于 3.11执行python --version改用typing_extensions导入,或升级 Python
cannot import name 'TypeGuard' from 'typing'Python 版本低于 3.10检查 Python 版本改用typing_extensions,或升级
安装了typing_extensions但依然报错环境中存在多个 Python 环境执行which pythonpip show typing_extensions确认 pip 和 python 属于同一虚拟环境
本地不报错,CI 报错CI 镜像 Python 版本和本地不一致查看 CI 日志中的python --version统一项目python_version配置,并用 Docker/venv 锁定

8.2 类型检查器行为差异

问题现象可能原因排查方式解决方案
mypy 通过,Pyright 报错两个工具对某些特性的实现细节不同查看具体错误行和规则名优先遵循 PEP 规范写法,而不是迁就某一工具
Pyright 通过,mypy 报错mypy 对动态类型更保守运行mypy --strict看详细报告pyproject.toml中按需放宽规则
类型检查通过,运行时却报错注解只用于检查,不影响运行时检查真实的数据结构修正数据构造逻辑,或使用cast明确类型
检查器大量标红第三方库缺少第三方库类型 stub查看是否安装了对应类型包安装types-requeststypes-PyYAML等 stub 包

8.3 工具安装类问题

问题现象可能原因排查方式解决方案
pyright命令找不到pip 安装版本未加入 PATH执行python -m pyright使用python -m pyright代替
mypy 安装后运行失败版本过旧或 Python 版本过新查看错误堆栈升级pip install -U mypy
项目里多个虚拟环境混乱没有使用虚拟环境工具查看当前环境路径统一使用venvuv管理环境

9. 工程建议:如何与 typing 生态相处

Basilisk 被移出 leaderboard,给我们的最大提醒是:工具不是永恒的,规范才是锚点。下面的工程建议可以直接用在你的项目里。

9.1 锁定 Python 和 typing_extensions 版本

如果你的项目需要兼容 Python 3.10 及以下版本,建议在requirements.txtpyproject.toml中显式引入:

typing_extensions>=4.8.0

这样,NotRequiredTypeGuardTypeVarTuple等新特性都可以通过typing_extensions安全导入。

9.2 编写“最小公倍数”风格注解

尽量使用所有主流检查器都能识别的规范写法,而不是某个工具的私有扩展。例如:

  • list[int]而不是List[int](前提是 Python 3.9+)。
  • X | Y而不是Optional[X](前提是 Python 3.10+)。
  • TypedDict时,优先从typing_extensions导入,以保持低版本兼容。

9.3 不要把检查器配置藏在 IDE 里

团队协作时,把 mypy/Pyright 的配置写进pyproject.toml,而不是让每个人在 IDE 里手动配置。这样才能保证 CI、本地开发、同事电脑上的检查口径一致。

9.4 关注 PEP 进度,但不盲目追新

Python 类型系统的演进很规律。每次新 PEP 发布,typing_extensions会先提供兼容实现,后续版本再进入标准库。建议开发团队每半年检查一次 Python 版本和 typing 特性支持情况,在版本约束允许的范围内逐步采用新写法。

9.5 用 CI 强制类型检查

把类型检查放入 CI 的最简单方式:

- name: Run type checks run: | pip install mypy pyright mypy app pyright app

这样工具是否还留在某个排行榜上,其实并不重要;重要的是你的项目已经建立了不依赖具体工具的“规范检查”流程。

10. 总结与后续学习方向

Basilisk 被移出 Python typing conformance leaderboard,不是一次简单的下架操作。它反映了 Python typing 生态正在从“功能竞争”进入“规范收敛”阶段:工具本身会更新换代,但 PEP 定义的类型规范才是各类工具共同遵循的基础。

对开发者来说,最实际的三点收获是:

  • 了解 leaderboard 的评测逻辑,不要轻信“工具 A 比工具 B 好”的结论,要看各自的适用场景。
  • 正确使用typing_extensions处理跨版本兼容,特别是NotRequiredTypeGuard这类新特性。
  • 在工程实践中,把代码规范建立在对 typing 规范的理解上,而不是绑定在某个具体工具上。

如果你对这个方向感兴趣,下一步可以从这几个点继续深入:

  1. 阅读 PEP 484、PEP 589、PEP 655、PEP 695 原文,建立对 typing 规范的系统认知。
  2. 在你的项目里同时接入 mypy 和 Pyright,观察两者的差异,理解“规范符合度”的实际含义。
  3. 研究typing_extensions源码,了解它是如何在旧版 Python 上模拟新特性的。

最后提醒一句:工具可以退出排行榜,但你的代码规范不必跟着某个工具走。理解规范、遵守规范,才是长期最优解。建议收藏这篇文章,下次再遇到ImportError: cannot import name 'NotRequired' from 'typing'时,直接按第 7 节的自查流程处理即可。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询