我创建了以下示例:
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]
,因此应该没有问题。
答案 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
。