假设我有一个Child类是类的子Parent类,以及一个接受Parent子类实例列表的函数:
from typing import List
class Parent:
pass
class Child(Parent):
pass
def func(objects: List[Parent]) -> None:
print(objects)
children = [Child()]
func(children)
Run Code Online (Sandbox Code Playgroud)
mypy在此运行会产生错误:
error: Argument 1 to "func" has incompatible type "List[Child]"; expected "List[Parent]"
Run Code Online (Sandbox Code Playgroud)
如何为此创建类型?
PS有一种方法可以使用Sequence类型修复此特定错误:
def func(objects: Sequence[Parent]) -> None:
print(objects)
Run Code Online (Sandbox Code Playgroud)
但这在其他类似情况下无济于事。我需要一个List,而不是一个Sequence。
在这里传递列表从根本上来说不是类型安全的。例如,如果你这样做呢?
def func(objects: List[Parent]) -> None:
print(objects)
objects.append(Parent())
children: List[Child] = [Child(), Child(), Child()]
func(children)
# Uh-oh! 'children' contains a Parent()!
Run Code Online (Sandbox Code Playgroud)
如果允许进行类型检查,您的代码最终将包含一个错误。
使用类型行话,List有意设计成不变类型。也就是说,即使Child是 的子类Parent,也不List[Child]是 的子类型List[Parent],反之亦然。您可以在此处和此处找到有关不变性的更多信息。
最常见的替代方法是使用Sequence它,它是一个只读的接口/协议/任何东西。并且由于 Sequence 是只读的,所以它是协变是安全的:也就是说,Sequence[Child]被认为是一个有效的子类型Sequence[Parent].
根据您的具体操作,您或许可以改用类型变量。例如,不是说“这个函数接受一个 Parent 的列表”,而是说“这个函数接受一个 Parent 或 Parent 子类的任何类的列表”:
TParent = TypeVar('TParent', bound=Parent)
def func(objects: List[TParent]) -> List[TParent]:
print(objects)
# Would not typecheck: we can't assume 'objects' will be a List[Parent]
objects.append(Parent())
return objects
Run Code Online (Sandbox Code Playgroud)
根据您的具体操作,您可以 maaaaaaaaybe 创建一个自定义协议,该协议定义了一个只写类列表的集合(或自定义数据结构)。并且由于您的数据结构将是只写的,您可以使其逆变——也就是说,WriteOnlyThing[Parent]将是WriteOnlyThing[Child]. 然后,您func接受WriteOnlyThing[Child]并可以安全地传递WriteOnlyThing[Child]和WriteOnlyThing[Parent]。
如果这两种方法都不适用于您的情况,您唯一的办法是要么使用# type: ignore消除错误(不推荐),放弃对列表内容进行类型检查并制作类型参数List[Any](也不推荐),要么找出如何重组您的代码以使其类型安全。
| 归档时间: |
|
| 查看次数: |
2100 次 |
| 最近记录: |