在泛型集合中指定重写方法的类型提示 [英] Specifying type hints of overridden methods in generic collection

查看:180
本文介绍了在泛型集合中指定重写方法的类型提示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我定义了一个抽象基类 BaseRepository ,它充当具有指定超类型 Foo 的项目集合。
BaseRepository 中的便利性classmethods被注释/类型暗示用于处理类型为 Foo 的对象。这里是一个简单的例子: $ ab
$ b

  from abc import ABCMeta,abstractmethod 
NoReturn = None

class Foo(object):
pass#简单数据保存对象

$ b $ class BaseRepository(object,metaclass = ABCMeta):

#可能是后面填充'Foo`的子类型
_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 ),它是原始泛型类型<$ c $的子类c> Foo 。

  class Bar(Foo):
pass#必须实现Foo为了使BaseRepository的方法能够工作
$ b $ def load_some_bars():
return [Bar(),Bar()]

class SubRepository(BaseRepository):
#从BaseRepository继承`get_item`

@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 用最小的努力(不会仅仅为了提示类型而重写它)。目前,尽管 SubRepository 拥有<$ c $, c> Bar
项目,我在PyCharm中的自动完成只显示 Foo 的成员。



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

解决方案

您正在编程接口,所以只有 foo 成员被暴露。

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

输出:

  {'return':< class'__main __。Foo'>} 

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

 从键入import TypeVar,Generic,get_type_hints 
from abc import ABCMeta,abstractmethod
NoReturn = None

#带有上限的类型变量
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]):
#从BaseRepository继承`get_item`

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

返回类型

  print(get_type_hints(SubRepository.get_item))

通过降价

  {'return':〜T} 

Autocompletion现在会显示 Bar的成员


I have defined an abstract base class BaseRepository that acts as a collection of items with specified supertype Foo. The convenience classmethods in BaseRepository are annotated/type hinted to work with objects of type Foo. Here is a minimal example:

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

Now there are multiple static implementations (e.g. SubRepository) which are each supposed to work with their own type of items (like Bar), being subclasses of the original generic type 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()

The repositories are static, meaning that they are not instantiated but rather function as namespaces for proper access to items that I load from YAML configuration files. The main perk is that I can create one of these SubRepositories and simply override the deserialization method _load_items, and the resulting repository will have all convenience methods from the base class. As I need to ensure that all of these SubRepositories work with items Foo that have a specific interface in order for the BaseRepository methods function properly, the SubRepositories must work with items that inherit from Foo.

Strongly-typed languages like Java or C# have the concept of Generic Collections, where the elements in the subclassed collections all assume a specific type. Is the same possible with type hinting in Python? In particular, I would like the inherited get_item method in SubRepository to be hinted as Bar with minimal effort (not override it just for the sake of type hints). Optimally, the correct return value should be linted by PyCharm.

Currently, even though SubRepository holds Bar items, my autocompletion in PyCharm only shows me members of Foo.

I read about typing.Generic and TypeVar, but I'm unsure how to use them in this case.

解决方案

You're programming to an interface, so only Foo members are exposed.

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

Output:

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

A generic collection will expose the generic type's members.

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()

Return type

print(get_type_hints(SubRepository.get_item))

Passes the buck

{'return': ~T}

Autocompletion will now show members of Bar.

这篇关于在泛型集合中指定重写方法的类型提示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆