我很难让类型暗示像我所期望的那样在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.TypeVar
和typing.Generic
try 更明确地指示Box
的每个子类将有一种单一类型的内容,Box.__getitem__
将返回该类型,对于IntBox
子类,该类型是int
.
我找到的唯一解决方案是,当我创建ib
时,我可以显式声明该实例的类型为IntBox[int]
,然后PyCharm会知道ib[0]
将是int
.但似乎我不需要每次创建IntBox
实例时都明确地说,相反,应该有某种方法让PyCharm从IntBox
的类声明中的[int]
推断出这一点,就像IntList
的情况一样.
当然,这只是一个玩具的例子.在激发这一点的实际情况中,我希望我的通用容器类"Box"定义其他方法(而不仅仅是__getitem__
),这些方法的类型暗示返回所讨论的"Box"子类始终包含的任何特定类型的对象,而这在不同的子类中有所不同.使用TypeVar
和Generic
我可以实现这一点,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]
可以使事情按预期进行.