能否在一个存根文件中使用另一个存根文件中的带类型注解的函数定义?
从其他.pyi存根文件导入类型定义的正确姿势
首先明确说:完全可以在一个存根文件里导入另一个存根的定义,你遇到的linter报错,大概率是存根文件的导入规则和普通Python文件略有差异,或者你的代码检查工具没正确识别存根文件导致的。下面一步步给你解决思路和正确做法:
一、先确认包结构和基础导入语法
首先得保证你的包结构是规范的,比如:
你的包名/ __init__.pyi extractor.pyi extractor.py # 对应的实际实现文件,必须和存根文件同名
在__init__.pyi里的导入本身语法是对的,但要注意两个点:
- 如果只是存根内部使用
_func,直接用from .extractor import _func没问题,但要确保linter知道这是存根之间的导入。 - 如果想把
_func暴露给包的外部使用者,可以加上__all__声明(不过下划线开头的函数通常不建议对外暴露,这里只是示例),同时要保证extractor.py里的_func和存根定义的接口完全一致——存根必须和实际代码的签名匹配,否则类型检查工具也会报错。
二、解决linter报错的常见方案
1. 让linter正确识别存根文件
像mypy、pyright这类工具,默认应该识别.pyi为存根,但有时候可能因为配置问题没生效:
- 对于mypy:确保你的包在mypy的扫描路径里,或者在
mypy.ini里加follow_imports = silent,用来兼容内部存根之间的导入。 - 对于pyright:检查
pyrightconfig.json的include配置,确保包含你的存根文件目录,它默认会优先读取.pyi的类型信息。
2. 加未来注解导入(可选)
如果你的存根用了较新的类型语法,在文件顶部加上:
from __future__ import annotations
可以避免一些导入时的类型解析冲突。
3. 确保存根和实际代码匹配
存根文件的核心作用是给类型检查工具提供接口信息,所以extractor.pyi里的_func签名必须和extractor.py里的实际函数完全一致(参数名、类型、返回值都要对应)。如果实文件里的函数和存根不匹配,linter或类型检查工具也会报错。
三、示例代码参考
extractor.pyi
def _func(arg: str) -> str: ...
init.pyi
# 内部使用的导入 from .extractor import _func # 如果需要对外暴露(可选,根据你的需求) # __all__ = ["_func"]
四、要避开的坑
- 别在存根文件里导入实际
.py文件的内容,存根之间的导入应该只在.pyi文件之间进行,不然就失去了存根提供类型信息的意义(存根不应该执行实际代码)。 - 存根文件名必须和对应的实际模块名完全一致,比如
extractor.pyi必须对应extractor.py,否则类型检查工具没法把两者关联起来。
内容的提问来源于stack exchange,提问作者Beliaev Maksim
相关产品推荐
相关产品推荐

