Python 中 Sized Iterable 的类型提示

新手上路,请多包涵

我有一个函数,它在其中一个参数上使用 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'])

这在使用 foolist 时会出错。

 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 许可协议

阅读 1.7k
1 个回答

从 Python3.6 开始,有一个名为 Collection 的新类型。看 这里

原文由 Avision 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题