我有一个函数,它在其中一个参数上使用 len
函数并迭代该参数。现在我可以选择是用 Iterable
还是用 Sized
来注释类型,但两者都会在 mypy
中给出错误
from typing import Sized, Iterable
def foo(some_thing: Iterable):
print(len(some_thing))
for part in some_thing:
print(part)
给予
error: Argument 1 to "len" has incompatible type "Iterable[Any]"; expected "Sized"
尽管
def foo(some_thing: Sized):
...
给予
error: Iterable expected
error: "Sized" has no attribute "__iter__"
由于没有 本期 讨论的 Intersection
,我需要某种混合类。
from abc import ABCMeta
from typing import Sized, Iterable
class SizedIterable(Sized, Iterable[str], metaclass=ABCMeta):
pass
def foo(some_thing: SizedIterable):
print(len(some_thing))
for part in some_thing:
print(part)
foo(['a', 'b', 'c'])
这在使用 foo
和 list
时会出错。
error: Argument 1 to "foo" has incompatible type "List[str]"; expected "SizedIterable"
这并不奇怪,因为:
>>> SizedIterable.__subclasscheck__(list)
False
所以我定义了一个 __subclasshook__
(见 文档)。
class SizedIterable(Sized, Iterable[str], metaclass=ABCMeta):
@classmethod
def __subclasshook__(cls, subclass):
return Sized.__subclasscheck__(subclass) and Iterable.__subclasscheck__(subclass)
然后子类检查工作:
>>> SizedIterable.__subclasscheck__(list)
True
但是 mypy
仍然抱怨我的 list
。
error: Argument 1 to "foo" has incompatible type "List[str]"; expected "SizedIterable"
在同时使用 len
函数并迭代我的参数时,如何使用类型提示?我认为铸造 foo(cast(SizedIterable, ['a', 'b', 'c']))
不是一个好的解决方案。
原文由 Benjamin 发布,翻译遵循 CC BY-SA 4.0 许可协议
从 Python3.6 开始,有一个名为
Collection
的新类型。看 这里。