我很难让类型暗示像我所期望的那样在PyCharm中定制容器子类的内容类型方面发挥作用.让我们从一个如我所料有效的 case 开始.您可以创建一个list的子类,并指定它总是有int个内容,然后Pycharm识别出这样一个列表中的每个项目都是int.

class IntList(list[int]): pass
il = IntList(())
answer1 = il[0]

当我将鼠标移到answer1上时,Pycharm说它希望这是int类型,可能是因为类声明指定IntList不是旧的list,而是list[int].(不要介意这段代码在运行时会引发错误,因为il是空的.这只是一个很小的例子,说明PyCharm有时可以从类声明中括号[int]中提取类型暗示信息.在其他情况下,从容器中获取项不会引发错误,也会出现同样的问题.)

因此,当从list子类化时,这很好地工作.但我想做的是创建自己的通用容器类,称之为Box,它可以包含各种不同类型的对象.然后我想声明我自己的子类IntBox,它只包含int个项目,我想让PyCharm在其各种鼠标悬停提示、自动完成建议和linting错误检测中识别这一点,就像它在IntList中一样.这是我想要的一个非常精简的例子.

class Box(list): pass
class IntBox(Box[int]): pass
ib = IntBox(())
answer2 = ib[0]

在这种情况下,当我将鼠标移到answer2上时,PyCharm说它可能有Any类型,但不知道[int]意味着这不仅仅是一个通用框/列表,而是一个其内容被类型暗示为int的框/列表.

我已经try 了我可以想象的所有变体,使用typing.TypeVartyping.Generictry 更明确地指示Box的每个子类将有一种单一类型的内容,Box.__getitem__将返回该类型,对于IntBox子类,该类型是int.

我找到的唯一解决方案是,当我创建ib时,我可以显式声明该实例的类型为IntBox[int],然后PyCharm会知道ib[0]将是int.但似乎我不需要每次创建IntBox实例时都明确地说,相反,应该有某种方法让PyCharm从IntBox的类声明中的[int]推断出这一点,就像IntList的情况一样.

当然,这只是一个玩具的例子.在激发这一点的实际情况中,我希望我的通用容器类"Box"定义其他方法(而不仅仅是__getitem__),这些方法的类型暗示返回所讨论的"Box"子类始终包含的任何特定类型的对象,而这在不同的子类中有所不同.使用TypeVarGeneric我可以实现这一点,if我显式地类型声明每个子类实例将包含一个特定的[contenttype],但如果没有对每个实例进行繁琐的显式类型声明,我无法找到使其工作的方法.

编辑:由于在告诉list子类中的元素的简单情况下工作的解决方案显然不会自动扩展到实际情况,因此这里有一个更接近我需要的示例,包括Box是嵌套的Sequence,而不是简单的list,包括Box.get_first()方法,该方法还应接收int for IntBox的类型提示,包括我认为TypeVar的大致正确用法:

from typing import TypeVar, Sequence
T = TypeVar('T')
class Box(Sequence[Sequence[T]]):
    def get_first(self:'Box[T]')->T:
        return self[0][0]
class IntBox(Box[int]): pass
ib = IntBox()  # works only if I declare this is type: IntBox[int]
answer = ib.get_first()  # hovering over answer should show it will be int

进一步编辑:前面的问题似乎是嵌套的Sequence[Sequence[T]].将此更改为Generic[T]可以使事情按预期进行.

推荐答案

使用typing.Generic将类型从使用typing.TypeVar的子类传递给Box超类

from typing import Generic, TypeVar

T = TypeVar('T')


class Box(Generic[T], list[T]):
    pass


class IntBox(Box[int]):
    pass


class StrBox(Box[str]):
    pass


ib = IntBox(())
answer1 = ib[0]  # int
sb = StrBox(())
answer2 = sb[0]  # str

Python相关问答推荐

为什么基于条件的过滤会导致pandas中的空数据框架?

在使用Guouti包的Python中运行MPP模型时内存不足

在上下文管理器中更改异常类型

在Python和matlab中显示不同 colored颜色 的图像

更改matplotlib彩色条的字体并勾选标签?

2维数组9x9,不使用numpy.数组(MutableSequence的子类)

如何将ctyles.POINTER(ctyles.c_float)转换为int?

根据在同一数据框中的查找向数据框添加值

将jit与numpy linSpace函数一起使用时出错

需要计算60,000个坐标之间的距离

通过Selenium从页面获取所有H2元素

Python—从np.array中 Select 复杂的列子集

如何合并两个列表,并获得每个索引值最高的列表名称?

* 动态地 * 修饰Python中的递归函数

在单次扫描中创建列表

基于行条件计算(pandas)

polars:有效的方法来应用函数过滤列的字符串

我对这个简单的异步者的例子有什么错误的理解吗?

如何求相邻对序列中元素 Select 的最小代价

每次查询的流通股数量