Jos*_*zer 4 python generics collections inheritance types
我定义了一个抽象基类BaseRepository,它充当具有指定 supertype 的项目的集合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
Run Code Online (Sandbox Code Playgroud)
现在有多个静态实现(例如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()
Run Code Online (Sandbox Code Playgroud)
存储库是静态的,这意味着它们没有被实例化,而是作为命名空间来正确访问我从 YAML 配置文件加载的项目。主要好处是我可以创建其中之一SubRepositories并简单地覆盖反序列化方法_load_items,并且生成的存储库将具有基类中的所有便利方法。由于我需要确保所有这些SubRepositories都与Foo具有特定接口的项目一起使用以使BaseRepository方法正常运行,因此SubRepositories必须与从Foo.
Java 或 C# 等强类型语言具有Generic Collections的概念,其中子类集合中的元素都采用特定类型。Python 中的类型提示是否可能相同?特别是,我希望以最小的努力来暗示继承的get_item方法(而不是仅仅为了类型提示而覆盖它)。最佳情况下,正确的返回值应该由 PyCharm 检测。SubRepositoryBar
目前,即使SubRepository持有Bar项目,我在 PyCharm 中的自动完成也只向我显示Foo.
我阅读了typing.Genericand TypeVar,但我不确定在这种情况下如何使用它们。
您正在对接口进行编程,因此只Foo公开成员。
from typing import get_type_hints
print(get_type_hints(SubRepository.get_item))
Run Code Online (Sandbox Code Playgroud)
输出:
{'return': <class '__main__.Foo'>}
Run Code Online (Sandbox Code Playgroud)
泛型集合将公开泛型类型的成员。
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()
Run Code Online (Sandbox Code Playgroud)
返回类型
print(get_type_hints(SubRepository.get_item))
Run Code Online (Sandbox Code Playgroud)
推卸责任
{'return': ~T}
Run Code Online (Sandbox Code Playgroud)
自动完成现在将显示Bar.