指定泛型集合中重写方法的类型提示

时间:2018-03-31 02:30:21

标签: python generics inheritance collections types

我已经定义了一个抽象基类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中的类型提示是否可以相同? 特别是,我希望get_item中的继承SubRepository方法以最小的努力被暗示为Bar(不仅仅为了类型提示而覆盖它)。最理想的是,PyCharm应该使用正确的返回值。

目前,即使SubRepository包含Bar个项目,我在PyCharm中的自动完成功能也只会显示Foo的成员。

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

1 个答案:

答案 0 :(得分:2)

您正在编程接口,因此只会公开expressionChangedAfterItHasBeenCheckedError个成员。

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} 的成员。