首页 > 解决方案 > 为什么列表列表不是序列列表?

问题描述

我创建了以下示例:

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

为什么在期待 a 时返回 a 是可以List[Circle]Sequence[Circle],但在期待 aList[List[Circle]]时却不能返回 a List[Sequence[Circle]]

更具体地说,当值是返回值时,为什么这不行?我想我理解为什么它不能作为参数,但我不明白为什么这个值不被接受为返回值。

文档给出了一个很好的例子来说明为什么Lists 是不变的:

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]并将它传递给认为它是 a 的东西List[Superclass],该函数可以编辑你的List[Subclass],以便它包含Superclass元素,所以它在函数运行后变成a 。List[Superclass]

但是,作为返回值,我不明白为什么这是一个问题。一旦它退出该功能,每个人都会将其视为 a List[Sequence[Circle]],它就是这样,所以应该没有问题。

标签: pythontypingmypy

解决方案


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

考虑以下情况:

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

在这里,Mypy 提出错误是绝对正确的,因为使用 的其他函数circle_list_matrix可能依赖于它是 a List[List[Circle]],但之后的其他函数可能会将其修改为 a List[Sequence[Circle]]

为了确定我们所处的情况,Mypy 必须跟踪我们的变量何时被声明,并确保List[List[Circle]] 在函数返回之后将返回值视为 a (即使它是这样输入的)在允许我们将其用作返回值之前。

(请注意,List[List[Circle]]在函数返回之前将其视为 a 不应该是一件坏事,因为List[List[Circle]]在那些点上它是 a 。此外,如果它总是被视为 a List[Sequence[Circle]],那么我们可以直接输入它没有问题。当某些东西将其视为 a 时就会出现问题List[List[Circle]],例如 with circle_list_matrix[0].append(Circle()),因此我们必须将其键入为 aList[List[Circle]]才能执行该操作,但List[Sequence[Circle]]在函数返回后每次都将其视为 a 。)

底线是 Mypy 不做那种分析。所以,为了让 Mypy 知道这没问题,我们应该直接转换它。

也就是说,我们知道返回值永远不会再被用作a 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导入typing

可以bar在问题代码中应用相同的铸造技术。


推荐阅读