我创建了以下示例:
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
为什么当它期望Sequence[Circle]
时可以返回List[Circle]
,而当它期望List[Sequence[Circle]]
时不能返回List[List[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]
,这样它就包含了Superclass
元素,这样在函数运行后它就变成了List[Superclass]
。你知道吗
但是,作为一个返回值,我不明白为什么这是一个问题。一旦它退出这个函数,每个人都会把它当作一个List[Sequence[Circle]]
,这就是,所以应该没有问题。你知道吗
再一次,在打这个问题的时候,我想我已经找到了答案。你知道吗
考虑以下情况:
在这里,Mypy提出这个错误是完全正确的,因为使用
circle_list_matrix
的其他函数可能依赖于它是List[List[Circle]]
,但是之后的其他函数可能会将它修改为List[Sequence[Circle]]
。你知道吗为了确定我们在哪种情况下,Mypy必须跟踪变量是何时声明的,并确保在允许我们将返回值用作返回值之前,不依赖于在函数返回之后将返回值视为
List[List[Circle]]
。你知道吗(请注意,在函数返回之前将其视为
List[List[Circle]]
应该不是坏事,因为在这些点上它是List[List[Circle]]
)。另外,如果它总是被当作一个List[Sequence[Circle]]
来处理,那么我们就可以毫无问题地这样键入它。当某些东西把它当作List[List[Circle]]
来处理时,问题就出现了,例如用circle_list_matrix[0].append(Circle())
,所以我们必须将它键入List[List[Circle]]
才能执行该操作,但是每次函数返回后它都被当作List[Sequence[Circle]]
)底线是Mypy不做这种分析。所以,为了让Mypy知道这是好的,我们应该投它。你知道吗
换句话说,我们知道返回值永远不会再用作
List[List[Circle]]
,因此baz
应该写成:其中
cast
是从typing
导入的。你知道吗同样的铸造技术可以应用于问题代码中的
bar
。你知道吗相关问题 更多 >
编程相关推荐