【问题标题】:Using Python typing's TypeVar for generically typed returns with bound使用 Python 类型的 TypeVar 进行泛型类型的返回绑定
【发布时间】:2021-02-12 03:12:51
【问题描述】:

当尝试使用类型的 TypeVar 来启用具有返回类型的泛型时,我遇到了一个 mypy 错误,即在比较字典的类型和预期的返回类型时,bound 参数没有被考虑在内一个函数。

以下是我面临的情况的示例:

from typing import Dict, List, Type, TypeVar


class Bird:
    def call(self):
        print(self.sound)


class Chicken(Bird):
    def __init__(self):
        self.sound = "bok bok"


class Owl(Bird):
    def __init__(self):
        self.sound = "hoot hoot"


T = TypeVar("T", bound=Bird)


class Instantiator:
    def __init__(self, birds: List[Type[Bird]]):
        self._bird_map: Dict[Type[Bird], Bird] = {}
        for bird in birds:
            self._bird_map[bird] = bird()

    def get_bird(self, bird_type: Type[T]) -> T:
        return self._bird_map[bird_type]

运行 mypy 验证器将显示:temp.py:29: error: Incompatible return value type (got "Bird", expected "T")

Instantiator 用作一种“跟踪器”,用于实例化每种鸟类中的一种。当尝试基于类类型检索实例化对象时,这就是为什么需要使用泛型,否则以后键入的字段将抱怨使用 Bird 类而不是 ChickenOwl 之一。

我在这里错误地使用了TypeVar 吗?有没有不同的方法来处理结构?这是 mypy 的疏忽吗?

【问题讨论】:

  • FWIW, i = Instantiator([Bird, Owl, Chicken]); b = i.get_bird(Owl); b.call() 在 Pycharm 中没有导致错误,并且它正确地将 b 识别为 Owl
  • 您的get_bird 也与the docs 中的make_new_user 相当接近。
  • 是的,谢谢@Carcigenicate,一切仍然正常,所有外部都可以正确输入。我看到错误只是字典类型与get_bird 函数的返回类型。如果使用 mypy 检查,我认为 PyCharm 仍会提示该错误?
  • 请注意,listdict 由于可变性而不变Dict[..., Bird] 包含 Birds 不包含子类。

标签: python mypy


【解决方案1】:

这是因为你定义了一个只包含基类对象Bird的dict,但是在函数get_bird中你试图返回一个基类类型的对象,而派生类的对象可能是预期的。 Mypy 不会使 Base -> Derived 演员。

您也可以将__init__ 设为通用函数。

T = TypeVar("T", bound=Bird)

class Instantiator():
    def __init__(self, birds: List[Type[T]]):
        self._bird_map: Dict[Type[T], T] = {}
        for bird in birds:
            self._bird_map[bird] = bird()

    def get_bird(self, bird_type: Type[T]) -> T:
        return self._bird_map[bird_type]

或者显式使用cast:

class Instantiator:
    def __init__(self, birds: List[Type[Bird]]):
        self._bird_map: Dict[Type[Bird], Bird] = {}
        for bird in birds:
            self._bird_map[bird] = bird()

    def get_bird(self, bird_type: Type[T]) -> T:
        return cast(T, self._bird_map[bird_type])  

【讨论】:

  • 因此,如果我想创建一个方法get_birds(),它返回给我一个类到实例化类的映射,我认为def get_birds(self) -> Dict[Type[T], T]: 会基于未知的泛型类型给我一个错误,但是因为那是全球范围内宣布的没问题?而且,像b: Dict[Type[Bird], Bird] = instantiator.get_birds() 这样的东西不会给出不兼容的类型错误?
猜你喜欢
  • 1970-01-01
  • 2017-08-23
  • 2014-08-25
  • 1970-01-01
  • 2018-08-03
  • 2021-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多