我在 python 中遇到的一个问题是 List 类型是不变的 - 这意味着它只能保存特定类型的对象,否则你会得到类型错误(例如运行 mypy 时) - 但有时你需要在更通用的函数中使用集合,该函数可以接受基类的所有类型(让我们称之为
A
)以及所有派生类。一个明显的例子是这个
class A:
pass
class B(A):
pass
def print_list_a(my_list: list[A]) -> None:
print(my_list)
l1 = [A()]
l2 = [B()]
# print_list_a(l1)
# print_list_a(l2)
当我在严格模式下使用 mypy 运行上述内容时,我得到以下内容
main.py:41: error: Argument 1 to "print_list_a" has incompatible type "list[B]"; expected "list[A]" [arg-type]
main.py:41: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
main.py:41: note: Consider using "Sequence" instead, which is covariant
处理这个问题的最佳方法是什么?使用协变而不是不变集合(即序列而不是列表)有什么好处?
我遇到了这个问题的两种解决方案。
一种是定义一个绑定到 A 的泛型类型,另一种是使用协变类型(如 Sequence),像这样
T = TypeVar('T', bound=A)
def print_list_t(my_list: List[T]) -> None:
print(my_list)
# This is fine!
print_list_t(l1)
print_list_t(l2)
# use covariant type Sequence in place of list
def print_sequence_a(my_sequence: Sequence[A]) -> None:
print(my_sequence)
# This is fine too because the sequence type is covariant
print_sequence_a(l1)
print_sequence_a(l2)
使用绑定类型的优点是类型
List
比Sequence更具体。但是,如果您很高兴您的函数可以接受任何类型的序列,那么使用这种协变类型会更容易。
您可以简单地将
l2
注释为 list[A]
:
class A:
pass
class B(A):
pass
def print_list_a(my_list: list[A]) -> None:
print(my_list)
l1: list[A] = [A()]
l2: list[A] = [B()]
print_list_a(l1)
print_list_a(l2)
此类型在 PyRight 中检查。