Python中大小Iterable的类型提示

2024-04-18 09:08:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个函数,它对它的一个参数使用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)

给予

^{pr2}$

同时

def foo(some_thing: Sized):
...

给予

error: Iterable expected
error: "Sized" has no attribute "__iter__"

由于没有this issue中讨论的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__(参见docs)。在

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']))不是一个好的解决方案。在


Tags: 函数lenfoodeferrorsomeiterablelist
3条回答

如果计划只使用list或tuple并按索引访问其元素,比如x[0],那么应该使用Sequencefrom{a1}。Sequence同时是Sized和{},请参见here。在

从Python3.6开始有一个新的类型叫做Collection。见here。在

将来将引入Protocols。它们已经通过^{}提供。另请参见PEP 544。使用Protocol以上代码将是:

from typing_extensions import Protocol


class SizedIterable(Protocol):

    def __len__(self):
        pass

    def __iter__(self):
        pass


def foo(some_thing: SizedIterable):
    print(len(some_thing))
    for part in some_thing:
        print(part)


foo(['a', 'b', 'c'])

mypy毫无怨言地接受该代码。但是PyCharm说

Expected type 'SizedIterable', got 'List[str]'

关于最后一行。在

相关问题 更多 >