在 Python 中使用适当的类型提示对序列进行子类化 [英] Subclassing Sequence with proper type hints in Python

查看:36
本文介绍了在 Python 中使用适当的类型提示对序列进行子类化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to implement a kind of custom sequence class in 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 类型的项目:

Now I want to check that mypy is aware that elements of MySequence are items of type T:

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

所以它失败了:mypyfoo 的项目一无所知.普通 Sequence 的相同示例有效:

So it fails: mypy knows nothing about items of foo. The same example for ordinary Sequence works:

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

如果我尝试将类型注释添加到 __getitem__ 实现,则会出现另一个错误:

If I'm trying to add type annotations to __getitem__ implementation, I have another error:

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

我也试过

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

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

as idx can be a slice and in that case my code will return a sequence instead of one element. It fails either with the same message.

我之前的问题所述,有对此类问题进行公开讨论.

As discussed in my previous question, there is an open discussion on issues like that.

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

However, I still wonder, is it possible to create custom sequence types that allow mypy to extract information about the type of its items, like in my example?

推荐答案

在这种情况下,正确的做法是正确覆盖 __getitem__ 的精确签名,包括重载.

In this case, the correct thing to do is to correctly override the exact signature for __getitem__, including the overloads.

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 协变.严格来说,这不是必需的,但如果容器有效地表示只读"类型的结构,我们不妨以获得最大的灵活性.)

(Note that I made the typevar covariant. This isn't, strictly-speaking, required, but if the container is effectively meant to represent a "read-only" kind of structure, we might as well for maximum flexibility.)

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

Note: the fact that mypy decides that the return type is Any in the first example is expected behavior. According to PEP 484, any method or signature without type annotations is treated as if the argument and return types are all Any.

这是一种机制,默认情况下,无类型的 Python 代码被视为完全动态的.

This is a mechanism designed so that untyped Python code is treated as fully dynamic by default.

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

Mypy comes built-in with a variety of command line arguments you can use to try and coerce it to check the contents of untyped functions anyways (I believe it's --check-untyped-defs?), though it won't attempt to infer what the return type is.

这篇关于在 Python 中使用适当的类型提示对序列进行子类化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆