Python 3.10合法模式匹配代码遭Mypy报错的原因咨询
为什么Mypy会对match-case中的动态类模式报错?
问题重现
你编写了一段使用Python模式匹配实现类型检查的代码,运行正常但Mypy抛出错误。核心代码和报错信息如下:
代码片段
from typing import Type, TypeVar def printTest(*args): ret = ltmItemFromIndex(*args) alt = ltmItemFromIndex_no_match(*args) test = 'Ok!' if (ret == alt) else 'Fail!' print(f"args: {args} | ret: {ret} | test: {test}", end="\n\n") class LineItem: pass class ObjectItem: pass class RecipeItem: pass LTM_ItemType = TypeVar("LTM_ItemType", LineItem, ObjectItem, RecipeItem) def ltmItemFromIndex(item, itemType: Type[LTM_ItemType]) -> LTM_ItemType | str | None: match item: case itemType(): print("case itemType():") return item case None: print("case None:") return None case _: print(error := f"TypeError: {type(item).__name__} instead of {itemType.__name__}!") return error def ltmItemFromIndex_no_match(item, itemType: Type[LTM_ItemType]) -> LTM_ItemType | str | None: if isinstance(item, itemType): return item elif item is None: return None else: return f"TypeError: {type(item).__name__} instead of {itemType.__name__}!" printTest(LineItem(), LineItem) printTest(None, LineItem) printTest(32, LineItem)
Mypy报错
main.py: error: Expected type in class pattern; found "Type[__main__.LineItem]" [misc] main.py: error: Expected type in class pattern; found "Type[__main__.ObjectItem]" [misc] main.py: error: Expected type in class pattern; found "Type[__main__.RecipeItem]" [misc]
错误原因
Mypy对match-case的类模式(class pattern)有严格的静态类型检查要求:类模式中必须是编译时就能确定的具体类型,不能是动态变量(哪怕这个变量是Type[LTM_ItemType]类型的参数)。
在你的代码里,case itemType()中的itemType是一个函数参数,Mypy在类型检查阶段无法确定它具体指向哪个类,因此会判定这个模式不符合静态类型规范。
而isinstance(item, itemType)能通过检查,是因为isinstance是运行时类型检查,Mypy可以通过TypeVar的约束(LineItem/ObjectItem/RecipeItem)推断出itemType的合法范围,从而确认类型检查的合理性。
解决方案
要保留模式匹配的写法同时通过Mypy检查,可以改用带类型守卫的模式匹配,把类型检查逻辑放到case的守卫条件里:
def ltmItemFromIndex(item, itemType: Type[LTM_ItemType]) -> LTM_ItemType | str | None: match item: case x if isinstance(x, itemType): print("case isinstance(x, itemType):") return x case None: print("case None:") return None case _: error = f"TypeError: {type(item).__name__} instead of {itemType.__name__}!" print(error) return error
这种写法既保留了模式匹配的语法,又让Mypy能够正确识别类型检查逻辑,不会再抛出错误,同时功能和原代码完全一致。
内容的提问来源于stack exchange,提问作者Jack Lilhammers
相关产品推荐
相关产品推荐

