是否存在协变的可变List版本?如何为指定函数参数标注类型?
问题解答
1. 是否存在协变的可变List版本?
不存在。Python的标准List是不变类型,而且没有内置的协变可变List实现——这是因为可变容器的协变会直接破坏类型安全。举个例子:如果List是协变的,那么List[int]可以被赋值给List[object],但此时你可以向List[object]中添加字符串,这会导致原本的List[int]中混入非整数类型,完全违背了静态类型检查的初衷。
2. 如何为print_it函数标注正确的参数类型?
你的核心需求是让参数既能接受List[int],又能接受支持索引赋值、元素为Optional[int]的可迭代类型。你尝试的几种类型之所以有问题,本质是因为可变序列类型(比如List、MutableSequence)都是不变的,所以List[int]无法兼容List[Optional[int]];而Sequence是只读的,不支持索引赋值。
最清晰且符合类型检查规范的方案是使用typing.overload,为函数定义两个重载签名,分别对应两种输入场景:
from typing import overload, List, Optional, MutableSequence @overload def print_it(numbers_or_nones: List[int]) -> None: ... @overload def print_it(numbers_or_nones: MutableSequence[Optional[int]]) -> None: ... def print_it(numbers_or_nones): for i, number in enumerate(numbers_or_nones): if number is None: numbers_or_nones[i] = 0 print("NOOOO") else: print(number) # 测试调用,类型检查器不会报错 numbers = [1, 2, 3, 4] print_it(numbers) mixed_numbers = [1, None, 3, None] print_it(mixed_numbers)
这样做的好处是:
- 当传入
List[int]时,类型检查器匹配第一个重载,明确知道函数不会修改列表元素(因为没有None值触发修改分支); - 当传入
MutableSequence[Optional[int]](比如List[Optional[int]])时,匹配第二个重载,允许索引赋值操作。
如果你不想使用overload,也可以用Union[List[int], MutableSequence[Optional[int]]]作为参数类型,但这种方式的泛型灵活性稍差,无法覆盖所有自定义的可变序列子类,而overload能更精准地描述函数的行为。
内容的提问来源于stack exchange,提问作者Martin Thoma
相关产品推荐
相关产品推荐

