为什么列表列表不是序列列表?

时间:2019-07-09 19:48:39

标签: python typing mypy

我创建了以下示例:

from typing import List, Sequence

class Circle:
    pass

def foo(circle: Circle) -> Sequence[Circle]:
    return_value: List[Circle] = [circle]
    return return_value

def bar(circle: Circle) -> List[Sequence[Circle]]:
    # Incompatible return value type (got "List[List[Circle]]", expected "List[Sequence[Circle]]")
    return_value: List[List[Circle]] = [[circle]]
    return return_value

为什么期望List[Circle]时返回Sequence[Circle]而不期望List[List[Circle]]时返回List[Sequence[Circle]]

更具体地说,当值是返回值时为什么还不行呢?我想我理解为什么它不能作为参数,但是我不明白为什么不将该值作为返回值。

文档提供了一个很好的示例,显示了List为何不变的原因:

class Shape:
    pass

class Circle(Shape):
    def rotate(self):
        ...

def add_one(things: List[Shape]) -> None:
    things.append(Shape())

my_things: List[Circle] = []
add_one(my_things)     # This may appear safe, but...
my_things[0].rotate()  # ...this will fail

在这里,想法是,如果您拿起List[Subclass]并将其传递给认为是List[Superclass]的东西,则该函数可以编辑List[Subclass]使其包含{{1} }元素,因此它在运行该函数后变为 Superclass

但是,作为返回值,我不明白为什么这是一个问题。退出该功能后,每个人都会将其视为List[Superclass],因此应该没有问题。

1 个答案:

答案 0 :(得分:0)

再一次输入这个问题时,我想我已经找到了答案。

请考虑以下情况:

List[Sequence[Circle]]

在这里,Mypy绝对可以提出该错误,因为使用from typing import List, Sequence class Circle: pass def baz(circle_list_matrix: List[List[Circle]]) -> List[Sequence[Circle]]: # Incompatible return value type (got "List[List[Circle]]", expected "List[Sequence[Circle]]") return circle_list_matrix 的其他功能可能取决于它是circle_list_matrix,但是此后其他功能可能会将其修改为{ {1}}。

为了确定我们处于哪种情况,Mypy必须跟踪变量的声明时间,并确保没有任何依赖于将返回值视为List[List[Circle]] 之后的情况。函数返回(即使它是这样键入的),然后才允许我们将其用作返回值。

(请注意,在函数返回之前将其视为List[Sequence[Circle]]并不是一件坏事,因为在这些时候它是List[List[Circle]]。如果始终将其视为List[List[Circle]],那么我们就可以毫无问题地键入它。问题是,当某人将其像List[List[Circle]]一样对待时,例如使用List[Sequence[Circle]],因此我们必须将其键入为List[List[Circle]]进行此操作,但在函数返回后,每次都将其视为circle_list_matrix[0].append(Circle())。)

最重要的是Mypy不会进行这种分析。因此,为了让Mypy知道这是可以的,我们应该将其投射。

换句话说,我们知道返回值将永远不会再用作List[List[Circle]],因此List[Sequence[Circle]]应该写为:

List[List[Circle]]

其中baz是从def baz(circle_list_matrix: List[List[Circle]]) -> List[Sequence[Circle]]: # works fine return cast(List[Sequence[Circle]], circle_list_matrix) 导入的。

可以将相同的转换技术应用于问题代码中的cast