Python中如何为函数参数标注父类及其子类的映射类型
如何标注接受父类或子类实例作为键的映射函数参数?
我想给函数takes_mapping的参数标注为「父类Parent或其子类实例与整数的映射」,但下面的代码触发了静态类型错误:
from collections.abc import Mapping class Parent: pass class Child(Parent): pass assert issubclass(Child, Parent) def takes_mapping(mapping: Mapping[Parent, int]): return child = Child() my_dict: dict[Child, int] = {child: 1} my_mapping: Mapping[Child, int] = {child: 1} takes_mapping(my_dict) # 类型错误 takes_mapping(my_mapping) # 同样的不变性错误
Pyright报错信息:
Argument of type "dict[Child, int]" cannot be assigned to parameter "mapping" of type "Mapping[Parent, int]" in function "takes_mapping" "dict[Child, int]" is not assignable to "Mapping[Parent, int]" Type parameter "_KT@Mapping" is invariant, but "Child" is not the same as "Parent" reportArgumentType
我的需求是让参数能接受键为Parent实例或任意子类实例的映射,而且后续可能新增Parent的子类,不想让标注和具体类层级耦合(Union不符合要求,因为得手动更新联合类型)。
解决方案
核心原因
Mapping的键类型参数是不变的:Mapping[Child, int]不能视为Mapping[Parent, int]的子类。因为如果函数尝试往映射中添加一个Parent类型的键,传入的dict[Child, int]根本无法容纳这类键——静态类型检查会阻止这种不安全的赋值。
正确的标注方式
使用TypeVar定义一个绑定到Parent的泛型类型,让函数接受任何键为Parent子类实例的映射:
from collections.abc import Mapping from typing import TypeVar class Parent: pass class Child(Parent): pass # 定义一个只能绑定到Parent或其子类的泛型类型 T = TypeVar('T', bound=Parent) def takes_mapping(mapping: Mapping[T, int]) -> None: # 函数内如果只读取映射(不添加/修改键),这个标注完全安全 for key in mapping: # key的类型会被推导为T(即Parent或其子类) assert isinstance(key, Parent) child = Child() my_dict: dict[Child, int] = {child: 1} my_mapping: Mapping[Child, int] = {child: 1} takes_mapping(my_dict) # 类型检查通过 takes_mapping(my_mapping) # 类型检查通过
方案优势
TypeVar的bound=Parent限制了T只能是Parent或其子类,确保映射的键都是Parent体系内的实例。- 后续新增
Parent的子类(比如GrandChild(Parent)),不需要修改函数的标注,直接传入dict[GrandChild, int]就能通过类型检查,完全解耦了标注和类层级。 - 如果函数只读取映射(不修改键),这个标注是类型安全的——不会出现往子类映射中添加父类键的风险。
如果函数完全不关心具体的键类型,只需要确认键是Parent的实例,也可以用简化写法(但泛型写法更灵活,能保留键的具体类型信息):
def takes_mapping(mapping: Mapping[Parent, int]) -> None: pass # 调用时显式告知类型检查器:my_dict的键都是Parent实例 takes_mapping(mapping=my_dict)
但最推荐的还是泛型写法,既满足类型安全,又能适配未来新增的子类。
内容的提问来源于stack exchange,提问作者philosofool
相关产品推荐
相关产品推荐

