【问题标题】:Specifying type hints of overridden methods in generic collection在泛型集合中指定重写方法的类型提示
【发布时间】:2018-09-10 00:56:27
【问题描述】:

我定义了一个抽象基类BaseRepository,它充当具有指定超类型Foo 的项的集合。 BaseRepository 中的便捷类方法经过注释/类型提示可与 Foo 类型的对象一起使用。这是一个最小的例子:

from abc import ABCMeta, abstractmethod
NoReturn = None

class Foo(object):
    pass  # simple data holding object


class BaseRepository(object, metaclass=ABCMeta):

    # May be filled with subtypes of `Foo` later
    _items = None  # type: List[Foo]

    @classmethod
    def get_item(cls) -> Foo:
        return cls._items[0]

    @classmethod
    @abstractmethod
    def _load_items(cls) -> NoReturn:
        pass

现在有多个静态实现(例如SubRepository),每个都应该使用自己的项目类型(例如Bar),它们是原始泛型类型Foo的子类。

class Bar(Foo):
    pass  # Must implement Foo in order for BaseRepository's methods to work

def load_some_bars():
    return [Bar(),Bar()]

class SubRepository(BaseRepository):
    # Inherits `get_item` from BaseRepository

    @classmethod
    def _load_items(cls) -> NoReturn:
        cls._items = load_some_bars()

存储库是静态的,这意味着它们不会被实例化,而是用作命名空间,以便正确访问我从 YAML 配置文件加载的项目。主要好处是我可以创建其中一个SubRepositories 并简单地覆盖反序列化方法_load_items,并且生成的存储库将具有来自基类的所有便利方法。因为我需要确保所有这些SubRepositories 与具有特定接口的项目Foo 一起使用,以便BaseRepository 方法正常运行,所以SubRepositories 必须与从Foo 继承的项目一起使用。

Java 或 C# 等强类型语言具有 通用集合 的概念,其中子类集合中的元素都假定为特定类型。 Python中的类型提示是否可能相同? 特别是,我希望以最小的努力将SubRepository 中继承的get_item 方法提示为Bar(不要仅仅为了类型提示而覆盖它)。最佳情况下,正确的返回值应该由 PyCharm 检测。

目前,即使 SubRepository 拥有 Bar 项目,我在 PyCharm 中的自动完成功能只显示 Foo 的成员。

我读到了 typing.GenericTypeVar,但我不确定在这种情况下如何使用它们。

【问题讨论】:

  • 可以使用 Python v3.5+ 吗?您也许可以使用typing 模块解决问题。我会让我的无知表现出来....您是否试图将其他语言的范式强加到 Python 中?您是实例化您的类还是将对象本身用作容器?
  • 是的,我正在寻找打字解决方案。我读到了Generic[...]TypeVar,但不确定它们在这种情况下有何帮助。对象本身是带有静态项的静态类,是的,因为它们代表我从 yaml 文件加载的配置值。
  • 需要明确的是,当方法套件只是对super 的方法的调用时,仅仅为了类型提示而重写该方法太费力了? --> def get_item(cls) -> Bar: return super().get_item()
  • 当然,这是我目前的解决方法。我可能还会查看 .pyi 文件,这些文件允许在单独的文件中指定类型提示,以防止混乱。但是,我正在寻找最惯用的解决方案,如果现在我们终于在 python 中拥有伪强类型,如果没有办法让它工作,我会感到惊讶 ????。顺便说一句,感谢您的编辑,感谢。
  • ...So if you really, really want type hints, there's really no alternative to specifying them everywhere you want them. 来自stackoverflow.com/a/22389249/2823755

标签: python generics inheritance collections types


【解决方案1】:

您正在对接口进行编程,因此只有Foo 成员被公开。

from typing import get_type_hints
print(get_type_hints(SubRepository.get_item))

输出:

{'return': <class '__main__.Foo'>}

泛型集合将公开泛型类型的成员。

from typing import TypeVar, Generic, get_type_hints
from abc import ABCMeta, abstractmethod
NoReturn = None

# type variable with an upper bound
T = TypeVar('T', bound=Foo)

class BaseRepository(Generic[T], metaclass=ABCMeta):
    _items = None  # type: List[T]

    @classmethod
    def get_item(cls) -> T:
        return cls._items[0]

    @classmethod
    @abstractmethod
    def _load_items(cls) -> NoReturn:
        pass

class SubRepository(BaseRepository[Bar]):
    # Inherits `get_item` from BaseRepository

    @classmethod
    def _load_items(cls) -> NoReturn:
        cls._items = load_some_bars()

返回类型

print(get_type_hints(SubRepository.get_item))

推卸责任

{'return': ~T}

自动补全现在将显示Bar 的成员。

【讨论】:

  • 我没有使用提示的 IDE。我不知道子类是否会显示正确的类型 - 我的只是显示 ~T
猜你喜欢
  • 2014-09-11
  • 1970-01-01
  • 1970-01-01
  • 2021-12-04
  • 2011-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多