类型提示名义继承错误预期类型“Tuple[A]”,却得到“Tuple[B,...]”

问题描述 投票:0回答:2

考虑以下事项:

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
,这是令人讨厌且错误的。

如何最好地处理这个问题?

python inheritance pycharm type-hinting python-typing
2个回答
2
投票

看看你的

return
声明:

return tuple([B()])

让我们稍微解开一下。

当然,

B()
的类型为
B

[B()]
是一个列表,具有
B
类型的单个元素。该列表的静态类型被推导为
list[B]
,即
B
实例的列表。

现在看

tuple([B()])
。您使用静态类型
tuple
的单个参数调用
list[B]
。如果您使用静态类型
tuple
的参数调用
list[B]
,则结果的静态类型为
tuple[B, ...]

这不是

tuple[A]
,甚至不是
tuple[B]
[B()]
的静态类型不包含任何长度信息,因此元组的类型也不包含任何长度信息。它只是一个包含一定数量
B
实例的元组。


问题是,你浏览了一份清单。你需要不要这样做。直接制作元组:

return (B(),)

然后静态分析器可以直接看到这是一个具有

B
类型的单个元素的元组,在预期为
tuple[A]
的上下文中,并推断出该元组可以而且应该被视为
tuple[A]


1
投票

如何最好地处理这个问题?

最简单的方法是返回文字声明而不是使用构造函数(语法也更简洁),如果将

return
写为:

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

但是您也可以使用构造函数,前提是它是从单个元素固定长度集合初始化的,PyCharm linter 不会抱怨,例如:

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

仔细查看错误信息:

got 'Tuple[B, ...]'

这里的省略号

...
意味着您要返回任意长度的元组(静态类型检查器推断出这一点,因为您使用列表初始化元组),而类型提示
-> Tuple[A]
需要固定长度的单元素元组,请参阅:

PEP 484

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

我使用 Python 3.8 和 Python 3.9 对此进行了测试(请注意,在该版本中

typing.Tuple
已被弃用,转而使用参数化内置函数进行类型提示。)

© www.soinside.com 2019 - 2024. All rights reserved.