我想暗示函数是类或其子类的实例与值之间的映射。下面的
takes_mapping
就是一个例子。但是,当我使用以下命令时,我遇到静态键入错误:
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) # typing error...
takes_mapping(my_mapping) # same basic error, involving invariance (see below)
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[Parent, ...]
,则函数的主体将尝试使用 Parent
键访问该字典,如果您传入 dict[Child, ...]
,则可能无法工作。 (它可以工作取决于你如何实现__hash__
,但你可以明白为什么mypy可能对此感到不安。)
为了解决这个问题,我认为你想使用
TypeVar
,它允许类型在 Parent
的范围内缩小:
from collections.abc import Mapping
from typing import TypeVar
class Parent:
pass
class Child(Parent):
pass
assert issubclass(Child, Parent)
_Parent = TypeVar("_Parent", bound=Parent)
def takes_mapping(mapping: Mapping[_Parent, int]):
# do stuff with the mapping, with some potentially-narrowed type for the mapping keys
return
child = Child()
my_dict: dict[Child, int] = {child: 1}
my_mapping: Mapping[Child, int] = {child: 1}
takes_mapping(my_dict) # ok (_Parent is bound to the Child type)
takes_mapping(my_mapping) # ok (same)