考虑以下事项:
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
,这是令人讨厌且错误的。
如何最好地处理这个问题?
看看你的
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]
。
如何最好地处理这个问题?
最简单的方法是返回文字声明而不是使用构造函数(语法也更简洁),如果将
return
写为:
def foo() -> Tuple[A]:
return B(),
但是您也可以使用构造函数,前提是它是从单个元素固定长度集合初始化的,PyCharm linter 不会抱怨,例如:
def foo() -> Tuple[A]:
return tuple((B(),))
仔细查看错误信息:
got 'Tuple[B, ...]'
这里的省略号
...
意味着您要返回任意长度的元组(静态类型检查器推断出这一点,因为您使用列表初始化元组),而类型提示 -> Tuple[A]
需要固定长度的单元素元组,请参阅:
- 元组,用于列出元素类型,例如
。空元组可以输入为Tuple[int, int, str]
。任意长度的同质元组可以使用一种类型和省略号来表示,例如Tuple[()]
。 (这里的Tuple[int, ...]
是语法的一部分,是字面省略号。)...
我使用 Python 3.8 和 Python 3.9 对此进行了测试(请注意,在该版本中
typing.Tuple
已被弃用,转而使用参数化内置函数进行类型提示。)