Python中兼具Sized与Iterable特性对象的类型注解问题
嘿,这个问题我之前也碰到过!你的函数foo需要参数同时满足两个核心要求:既能用len()获取长度,又能被遍历,但单独用Iterable或Sized类型注解都只覆盖了其中一个条件,所以mypy会抛出类型不兼容的错误。
为什么单独用不行?
- 当你标注
some_thing: Iterable时,mypy知道这个对象支持遍历,但不确定它有__len__方法,所以调用len()会触发类型错误; - 当你标注
some_thing: Sized时,mypy知道它有长度,但不确定它支持遍历,所以for循环会报错。
解决方案1:用交集类型明确约束(推荐)
如果你用的是Python 3.10+,可以直接用|语法表示“同时满足两种类型”,或者用Intersection类型来更明确地表达交集关系:
方式A:Python 3.10+ 简洁语法
from typing import Iterable, Sized def foo(some_thing: Iterable | Sized): print(len(some_thing)) for part in some_thing: print(part)
方式B:用Intersection(更严谨)
from typing import Iterable, Sized, Intersection def foo(some_thing: Intersection[Iterable, Sized]): print(len(some_thing)) for part in some_thing: print(part)
如果是Python 3.9及以下,可以安装typing_extensions库,导入其中的Intersection来使用。
解决方案2:自定义Protocol(适合频繁复用场景)
如果你的项目里经常需要这种“可遍历且有长度”的类型,自定义一个Protocol会让代码可读性更强:
from typing import Protocol, Iterable, Sized # 定义一个同时继承Iterable和Sized的协议 class IterableWithLength(Protocol, Iterable, Sized): pass def foo(some_thing: IterableWithLength): print(len(some_thing)) for part in some_thing: print(part)
这个协议会自动要求实现它的对象同时具备__iter__(支持遍历)和__len__(支持len())方法,mypy能完美识别这种约束。
验证一下
不管用哪种方案,像列表、元组、字符串这些同时满足两个条件的对象,都能正常传入foo,而像生成器(只满足Iterable,不满足Sized)这种对象,mypy会提前帮你拦截错误,这正是我们想要的类型检查效果!
内容的提问来源于stack exchange,提问作者Benjamin
相关产品推荐
相关产品推荐

