gpt4 book ai didi

python - 如何为可迭代抽象基类编写类型提示?

转载 作者:行者123 更新时间:2023-12-05 04:22:38 31 4
gpt4 key购买 nike

我需要为以下类编写一个抽象基类:

  • 派生自现有类 SomeClassIHaveToDeriveFrom(这就是我不能使用 Protocol 的原因,我需要它作为抽象基类),
  • 实现Iterable接口(interface),
  • 包含特定类型的对象,Element(即,如果我们迭代一个实例,我们会得到类型为 Element 的对象)。

我试图在抽象基类中向 __iter__ 添加类型提示:

import abc
import collections.abc
import typing

class Element:
pass

class SomeClassIHaveToDeriveFrom:
pass

class BaseIterableClass(
abc.ABC,
collections.abc.Iterable,
SomeClassIHaveToDeriveFrom,
):
@abc.abstractmethod
def __iter__(self) -> typing.Iterator[Element]:
...

class A(BaseIterableClass):
def __iter__(self):
return self

def __next__(self):
return "some string that isn't an Element"

a = A()
a_it = iter(a)
a_el = next(a)

但是 mypy 在这里没有检测到任何错误,即使 a 是一个包含 strBaseIterableClass 实例>s 而不是 Elements。我假设 __iter__ 受到名称修改的影响,这意味着类型提示被忽略。

我如何输入提示 BaseIterableClass 以便使用迭代 Element 以外的东西的 __iter__ 函数派生它会导致输入错误?

最佳答案

--strict 模式下运行 mypy 实际上会告诉您所需的一切。

1) 不完整的可迭代

:13: error: Missing type parameters for generic type "Iterable"  [type-arg]

因为 Iterable 是通用的并且 parameterized对于一个类型变量,你应该相应地对其进行子类化,即

...
T = typing.TypeVar("T", bound="Element")
...
class BaseIterableClass(
abc.ABC,
collections.abc.Iterable[T],
SomeClassIHaveToDeriveFrom,
):

2) 现在我们得到一个新的错误

:17: error: Return type "Iterator[Element]" of "__iter__" incompatible with return type "Iterator[T]" in supertype "Iterable"  [override]

容易解决:

...
@abc.abstractmethod
def __iter__(self) -> typing.Iterator[T]:

3) 现在我们使 BaseIterableClass 正确通用...

:20: error: Missing type parameters for generic type "BaseIterableClass"  [type-arg]

这里我们可以指定Element:

class A(BaseIterableClass[Element]):
...

4) 缺少返回类型

:21: error: Function is missing a type annotation  [no-untyped-def]
:24: error: Function is missing a return type annotation [no-untyped-def]

由于我们正在为 A 定义方法 __iter____next__,我们需要正确地注释它们:

...
def __iter__(self) -> collections.abc.Iterator[Element]:
...
def __next__(self) -> Element:

5) 返回值错误

既然我们注释了 __next__ 返回类型,mypy 会选择 "some string that isn't an Element" 不是,事实上,Element 的一个实例。 🙂

:25: error: Incompatible return value type (got "str", expected "Element")  [return-value]

完整注释的代码

from abc import ABC, abstractmethod
from collections.abc import Iterable, Iterator
from typing import TypeVar


T = TypeVar("T", bound="Element")


class Element:
pass


class SomeClassIHaveToDeriveFrom:
pass


class BaseIterableClass(
ABC,
Iterable[T],
SomeClassIHaveToDeriveFrom,
):
@abstractmethod
def __iter__(self) -> Iterator[T]:
...


class A(BaseIterableClass[Element]):
def __iter__(self) -> Iterator[Element]:
return self

def __next__(self) -> Element:
return "some string that isn't an Element" # error
# return Element()

固定类型参数

如果您不希望BaseIterableClass 是通用的,您可以更改步骤1)-3) 并为所有子类指定类型参数。然后您不需要为 A 传递类型参数。代码将如下所示:

from abc import ABC, abstractmethod
from collections.abc import Iterable, Iterator


class Element:
pass


class SomeClassIHaveToDeriveFrom:
pass


class BaseIterableClass(
ABC,
Iterable[Element],
SomeClassIHaveToDeriveFrom,
):
@abstractmethod
def __iter__(self) -> Iterator[Element]:
...


class A(BaseIterableClass):
def __iter__(self) -> Iterator[Element]:
return self

def __next__(self) -> Element:
return "some string that isn't an Element" # error
# return Element()

也许用 Iterator 代替?

最后,您似乎确实需要 Iterator 接口(interface),因为您在子类 A 上定义了 __next__ 方法。在这种情况下,您根本不需要定义 __iter__Iterator 继承自 Iterable 并自动混合 __iter__,当您从它继承并实现 __next__ 时。 (参见 docs)

此外,由于 Iterator 基类已经是抽象的,您不需要将 __next__ 作为抽象方法包含在内。

那么(通用版本的)代码将如下所示:

from abc import ABC
from collections.abc import Iterator
from typing import TypeVar


T = TypeVar("T", bound="Element")


class Element:
pass


class SomeClassIHaveToDeriveFrom:
pass


class BaseIteratorClass(
ABC,
Iterator[T],
SomeClassIHaveToDeriveFrom,
):
pass


class A(BaseIteratorClass[Element]):
def __next__(self) -> Element:
return "some string that isn't an Element" # error
# return Element()

iter(A())next(A()) 都有效。

希望这对您有所帮助。

关于python - 如何为可迭代抽象基类编写类型提示?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73933419/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com