创建带类型标注的类方法装饰器,跨文件导入使用时mypy报错如何解决
问题解决方案
根因说明
这个报错本质是跨文件导入时,mypy未将你的项目包识别为支持类型检查的合法包,无法读取Subscriber类topic方法的类型标注,因此将装饰器判定为无类型实现。同文件使用不报错是因为mypy可直接读取当前文件内的类型定义,符合你观察到的现象。
分步解决步骤
- 补全包标识文件
- 虽然Python 3.3+支持无
__init__.py的隐式命名空间包,但mypy对该特性的支持不完善,优先在每一级包目录下添加空的__init__.py文件,路径如下:organization/__init__.pyorganization/namespace/__init__.pyorganization/namespace/package/__init__.pyorganization/namespace/package/mqtt/__init__.py
- 在
organization/namespace/package/mqtt/目录下新增空的py.typed文件,该文件是PEP 561规定的标识,用来告知mypy当前目录下的包包含合法类型标注,需要纳入类型检查。
- 虽然Python 3.3+支持无
- 校验mypy配置
打开你项目根目录下的pyproject.toml、mypy.ini或.mypyrc配置文件,检查两项配置:- 你的项目包路径未被加入
exclude排除列表,避免mypy跳过该包的类型扫描 - 不要将你的项目包加入
ignore_missing_imports对应的包列表,否则mypy会直接跳过该包的类型检查
- 你的项目包路径未被加入
- 修正代码笔误
你使用装饰器的文件里导入行存在语法错误,把重复的from去掉:
# 错误写法 from from organization.namespace.package.mqtt.client import Subscriber # 正确写法 from organization.namespace.package.mqtt.client import Subscriber
- 可选优化(非必须,可提升类型推断准确性)
将TypeVar的作用域调整到方法层面,避免全局TypeVar可能带来的推断异常:
from json import loads from typing import TypeVar, Callable, Any, Optional, Dict, Union F = TypeVar("F", bound=Callable[..., None]) class Subscriber: """Decorate topic handlers. Must register the subscriber with register_subscriber.""" def __init__(self) -> None: self.handlers: Dict[str, tuple] = dict() def topic( self, topic: str, parse_func: Optional[Callable[[Union[str, bytes]], Any]] = loads ) -> Callable[[F], F]: """Subscribe to mqtt topic. by default the response is parsed with json.loads and passed into the handler. Override this with a custom parser or set it to None to receive the raw response.""" def add_handler(handler: F) -> F: self.handlers[topic] = (handler, parse_func) return handler return add_handler
验证
修改完成后执行以下命令检查是否还有报错:
mypy organization/namespace/package/mqtt/handler.py
内容的提问来源于stack exchange,提问作者The Fool
相关产品推荐
相关产品推荐

