Python类型注解:如何指定变量同时具备多种类型?
解决Python类型注解中“同时具备多种类型”的标注问题
核心结论
要表示变量同时具备多种类型(而非二选一),Python类型系统支持交集类型(使用&符号),这正是你要找的类似Union但表示“且”的标注方式。此外,也可以通过自定义Protocol来定义复合类型。
针对你的场景的解决方案
你遇到的mypy报错,本质是Iterable本身不包含__len__方法(不属于Sized类型),因此直接对Iterable调用len()会触发类型检查错误。下面提供两种可行方案:
方案1:直接使用交集类型标注
Python 3.10+和mypy都支持用&表示交集类型,直接标注参数同时是Iterable和Sized:
from typing import Iterable, Sized, TypeVar D1 = TypeVar('D1') D2 = TypeVar('D2') def your_function(a: Iterable[D1] & Sized, b: Iterable[D2] & Sized) -> int: return len(a) + len(b)
这样mypy会识别到a和b同时具备Iterable的迭代能力和Sized的len()方法,不会再报错。
方案2:自定义复合类型Protocol
如果需要多次复用这个复合类型,可以用Protocol定义一个同时继承Iterable和Sized的协议(无需实现任何方法,只需定义结构):
from typing import Iterable, Sized, Protocol, TypeVar T = TypeVar('T') class SizedIterable(Iterable[T], Sized, Protocol): """同时具备Iterable和Sized特性的类型""" pass # 之后就可以直接用这个自定义类型标注 def your_function(a: SizedIterable[D1], b: SizedIterable[D2]) -> int: return len(a) + len(b)
像list、tuple、set这类内置类型,天然符合SizedIterable的结构,传入它们不会触发类型错误。
为什么你之前的泛型类方案失效?
如果之前直接定义普通泛型类(而非Protocol):
# 错误示例:普通类需要实现抽象方法,无法直接用于类型标注 from typing import Iterable, Sized, Generic, TypeVar T = TypeVar('T') class SizedIterable(Generic[T], Iterable[T], Sized): pass
这种方式要求类必须实现Iterable和Sized的抽象方法(比如__iter__、__len__),但你实际传入的对象(比如list)并不是这个类的实例,因此会出现类型不兼容错误。而Protocol是结构类型检查,只要对象满足协议定义的方法/属性,就会被视为符合类型。
内容的提问来源于stack exchange,提问作者Troy Daniels
相关产品推荐
相关产品推荐

