对于返回与其输入之一类型相同的序列的函数,正确的类型注释是什么?

问题描述 投票:0回答:1

对于Python代码

from typing import TypeVar, Sequence, Iterator

S = TypeVar("S", bound=Sequence)

def chunk(data: S) -> S:
    return data[:]

mypy 0.971 报告错误

simple_8.py:6:12:错误:返回值类型不兼容(得到“Sequence[Any]”,预期“S”)[返回值]

这个例子中的类型注释错误在哪里?注释这个函数的正确、精确的方法是什么?

python python-typing mypy
1个回答
2
投票

如果你看一下Typeshed

Sequence
的定义:

class Sequence(Collection[_T_co], Reversible[_T_co], Generic[_T_co]):
    @overload
    @abstractmethod
    def __getitem__(self, index: int) -> _T_co: ...
    @overload
    @abstractmethod
    def __getitem__(self, index: slice) -> Sequence[_T_co]: ...

您可以看到

seq[:]
保证返回 some
Sequence
,其泛型类型
_T_Co
作为源,但它 not 不一定是相同类型的序列。尽管内置序列类型通常具有这种行为,例如对于
list

    @overload
    def __getitem__(self, __s: slice) -> list[_T]: ...
                                       # ^ concrete list not abstract Sequence

这不是接口的要求。

由于您没有向

Sequence
中的
TypeVar
提供泛型类型,因此它是默认的
Any
,因此出现错误:

error: Incompatible return value type (got "Sequence[Any]", expected "S") [return-value]

切片

data[:]
给出
Sequence[Any]
,其可能
S
相同,但不是必需。因此,如果您想支持任何
Sequence
,最精确的可以是:

from typing import Sequence, TypeVar

T = TypeVar("T")

def chunk(data: Sequence[T]) -> Sequence[T]:
    return data[:]

游乐场


或者,如果您使用更严格的类型定义

Protocol
,则
seq[:]
必须 返回相同的类型:

from typing import Protocol, TypeVar

T = TypeVar("T")

class StrictSlice(Protocol):
    def __getitem__(self: T, index: slice) -> T: ...

然后您可以将其用作

bound
中的
S
类型并获得类型保留行为:

S = TypeVar("S", bound=StrictSlice)

def chunk(data: S) -> S:
    return data[:]

l: list[int] = chunk([1, 2, 3])
s: str = chunk("Hello, world!")

如果您使用

Sequence[T]
尝试此操作,您会得到例如
expression has type "Sequence[int]", variable has type "List[int]"

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.