Еще раз, набирая этот вопрос, я думаю, что нашел ответ на него.
Рассмотрим следующий случай:
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
, могут зависеть от того, что это 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
должен быть записан в виде:
def baz(circle_list_matrix: List[List[Circle]]) -> List[Sequence[Circle]]:
# works fine
return cast(List[Sequence[Circle]], circle_list_matrix)
, где cast
импортируется из typing
.
Тот же самый метод приведения может применяться к bar
в коде вопроса.