pycharm 类型提示名义继承Bug应为类型“Tuple[A]”,但得到了“Tuple[B,...]”

kzipqqlq  于 2022-11-08  发布在  PyCharm
关注(0)|答案(2)|浏览(330)

请考虑以下事项:

from typing import Tuple

class A(object):
    def __init__(self):
        pass

class B(A):
    def __init__(self):
        super(B, self).__init__()

def foo() -> Tuple[A]:
    return tuple([B()])

foo()

PyCharm会发出警告:
Expected type 'Tuple[A]', got 'Tuple[B, ...]' instead
tuple([B()])上。
由于B“是一个”A,这是恼人的和错误的。
如何最好地处理这一问题?

svmlkihl

svmlkihl1#

看看你的return陈述:

return tuple([B()])

让我们把它拆开一点。
当然,B()的类型是B
[B()]是一个列表,具有类型为B的单个元素。此列表的静态类型被推导为list[B],即B示例的列表。
现在看看tuple([B()]),你用一个静态类型list[B]的参数调用tuple,如果你用一个静态类型list[B]的参数调用tuple,结果的静态类型是tuple[B, ...]
它不是tuple[A],甚至不是tuple[B][B()]的静态类型不包含任何长度信息,所以元组的类型也不包含任何长度信息。它只是一个包含一些B示例的元组。
问题是,你已经遍历了一个列表,你不需要这样做,直接生成一个元组:

return (B(),)

然后,静态分析器可以直接看到,这是一个元组,其中有一个B类型的元素,在一个上下文中,一个tuple[A]是预期的,并推断出该元组可以和应该被视为一个tuple[A]

aamkag61

aamkag612#

如何最好地处理这一问题?
最简单的方法是返回文本声明而不是使用构造函数(语法也更简洁),如果您将return写为:

def foo() -> Tuple[A]:
    return B(),

但是,如果构造函数是从单个元素的固定长度集合初始化的,那么您也可以使用该构造函数,PyCharm编译器不会对此不满,例如:

def foo() -> Tuple[A]:
    return tuple((B(),))

仔细查看错误消息:
got 'Tuple[B, ...]'
这里的省略号...表示您返回的是任意长度的元组(静态类型检查器会推断出这一点,因为您使用列表初始化元组),而类型提示-> Tuple[A]需要一个固定长度的单元素元组,请参见:
人教版484

  • 元组,用于列出元素类型,例如Tuple[int, int, str]。空元组的类型可以是Tuple[()]。任意长度的同类元组可以使用一种类型和省略号来表示,例如Tuple[int, ...]。(此处的...是语法的一部分,即文字省略号。)

我用Python 3.8和Python 3.9测试了这一点(请注意,这是typing.Tuple被弃用而改用参数化内置函数进行类型提示的版本)。

相关问题