对于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”)[返回值]
这个例子中的类型注释错误在哪里?注释这个函数的正确、精确的方法是什么?
如果你看一下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]"
。