重写Formatter.parse方法时mypy报错str与StrOrLiteralStr不兼容
问题解析与修复
问题原因
1. 元组元素的可选性不兼容
父类Formatter.parse的返回元组中,第2至第4个元素(对应field、spec、conversion)被定义为StrOrLiteralStr | None,即允许返回None;但你的子类返回的这三个元素都是非None的str,这违反了方法重写的类型协变规则——子类返回类型不能比父类更严格,否则依赖父类返回可能为None的调用者会出现逻辑错误。
2. StrOrLiteralStr与str的类型差异
StrOrLiteralStr是string模块内置的类型别名,等价于str | LiteralString。LiteralString是mypy的特殊类型,用于标记字面量字符串(如直接编写的"a"),它是str的子类型。父类允许返回LiteralString或普通str,而子类仅返回普通str,在mypy的严格检查下会被判定为类型范围不匹配。
修复方法
方法一:严格匹配父类返回类型
直接将子类parse方法的返回类型改为与父类完全一致,这是最规范的解决方案:
from string import Formatter, StrOrLiteralStr from typing import Iterable, Tuple, Optional class MyFormatter(Formatter): def parse(self, s: str) -> Iterable[Tuple[StrOrLiteralStr, Optional[StrOrLiteralStr], Optional[StrOrLiteralStr], Optional[StrOrLiteralStr]]]: for text, field, spec, conversion in super().parse(s): yield "a", "b", "c", "d"
方法二:使用字面量字符串类型(适用于固定字面量场景)
如果你的yield内容都是静态字面量字符串,可以将返回类型中的str替换为LiteralString,既满足StrOrLiteralStr的要求,也能准确反映代码逻辑:
from string import Formatter from typing import Iterable, Tuple, LiteralString class MyFormatter(Formatter): def parse(self, s: str) -> Iterable[Tuple[LiteralString, LiteralString, LiteralString, LiteralString]]: for text, field, spec, conversion in super().parse(s): yield "a", "b", "c", "d"
注意:此方法仅适用于返回内容始终是字面量的情况,若后续需要动态生成字符串,建议使用方法一。
方法三:忽略类型检查(不推荐)
如果必须保持当前返回类型,可以添加注释绕过mypy的报错,但这会丢失类型检查的保护,可能隐藏潜在问题:
from string import Formatter from typing import Iterable, Tuple class MyFormatter(Formatter): def parse(self, s: str) -> Iterable[Tuple[str, str, str, str]]: # type: ignore[override] for text, field, spec, conversion in super().parse(s): yield "a", "b", "c", "d"
内容的提问来源于stack exchange,提问作者solaluset
相关产品推荐
相关产品推荐

