在 Python 中使用正确的类型提示对序列进行子类化

2023-11-23

我正在尝试在 Python 中实现一种自定义序列类:

from typing import Sequence, TypeVar, List

T = TypeVar('T')

class MySequence(Sequence[T]):
    def __init__(self):
        self._container: Sequence[T] = []
    def __getitem__(self, idx):
        return self._container[idx]
    def __len__(self):
        return len(self._container)

现在我想检查一下mypy知道元素MySequence是类型的项目T:

foo: MySequence[str] = MySequence()
reveal_type(foo[0])
# Revealed type is 'Any'

所以它失败了:mypy对以下物品一无所知foo。普通的同样的例子Sequence works:

bar: Sequence[str] = []
reveal_type(bar[0])
# Revealed type is 'builtins.str*'

如果我尝试添加类型注释__getitem__实施,我有另一个错误:

def __getitem__(self, idx) -> T:
# Signature of "__getitem__" incompatible with supertype "Sequence"

我也尝试过

def __getitem__(self, idx) -> Union[T, Sequence[T]]:

as idx可以是一个切片,在这种情况下,我的代码将返回一个序列而不是一个元素。它要么失败并显示相同的消息。

正如中所讨论的我之前的问题, 有一个公开讨论诸如此类的问题。

但是,我仍然想知道,是否可以创建自定义序列类型来允许mypy提取有关其项目类型的信息,就像在我的示例中一样?


在这种情况下,正确的做法是正确覆盖准确签名__getitem__,包括过载。

from typing import Sequence, TypeVar, List, overload, Union

T = TypeVar('T', covariant=True)

class MySequence(Sequence[T]):
    def __init__(self):
        self._container: Sequence[T] = []

    @overload
    def __getitem__(self, idx: int) -> T: ...

    @overload
    def __getitem__(self, s: slice) -> Sequence[T]: ...

    def __getitem__(self, item):
        if isinstance(item, slice):
            raise Exception("Subclass disallows slicing")

        return self._container[item]

    def __len__(self) -> int:
        return len(self._container)

foo: MySequence[str] = MySequence()
reveal_type(foo[0])

(请注意,我制作了 typevar 协变。严格来说,这不是必需的,但如果容器实际上意味着表示“只读”类型的结构,我们不妨获得最大的灵活性。)


注意:在第一个示例中 mypy 决定返回类型为 Any ,这是预期的行为。根据 PEP 484,任何没有类型注释的方法或签名都被视为参数和返回类型都是Any.

这是一种机制,旨在默认情况下将非类型化 Python 代码视为完全动态的。

Mypy 内置了各种命令行参数,您可以使用它来尝试强制它检查无类型函数的内容(我相信它是--check-untyped-defs?),但它不会尝试推断返回类型是什么。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Python 中使用正确的类型提示对序列进行子类化 的相关文章

随机推荐