如何在Python中将函数的参数提示为具有父类的字典

问题描述 投票:0回答:1

我想暗示函数是类或其子类的实例与值之间的映射。下面的

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
不会真正表达所需的内容,因为它取决于特定的联合类型。

python python-typing
1个回答
0
投票

问题是,如果函数被输入为采用

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)
© www.soinside.com 2019 - 2024. All rights reserved.