我不明白应该如何在代码中使用 ArrayLike。如果检查 mypy,当我尝试在不调用强制转换的情况下使用变量进行任何操作时,我会不断收到错误。我正在尝试定义与 ndarray 以及常规列表一起使用的函数签名。
例如下面的代码
import numpy.typing as npt
import numpy as np
from typing import Any
def f(a: npt.ArrayLike) -> int:
return len(a)
def g(a: npt.ArrayLike) -> Any:
return a[0]
print(f(np.array([0, 1])), g(np.array([0, 1])))
print(f([0, 1]), g([0, 1]))
给我 f() 和 g() 的这些错误:
Argument 1 to "len" has incompatible type "Union[_SupportsArray[dtype[Any]], _NestedSequence[_SupportsArray[dtype[Any]]], bool, int, float, complex, str, bytes, _NestedSequence[Union[bool, int, float, complex, str, bytes]]]"; expected "Sized" [arg-type]
Value of type "Union[_SupportsArray[dtype[Any]], _NestedSequence[_SupportsArray[dtype[Any]]], bool, int, float, complex, str, bytes, _NestedSequence[Union[bool, int, float, complex, str, bytes]]]" is not indexable [index]
最佳答案
numpy.typing.ArrayLike
的目的就是能够注释
objects that can be coerced into an
ndarray
.
考虑到这一目标,他们 defined the type成为以下联合体:
Union[
_SupportsArray[dtype[Any]],
_NestedSequence[_SupportsArray[dtype[Any]]],
bool,
int,
float,
complex,
str,
bytes,
_NestedSequence[Union[bool, int, float, complex, str, bytes]]
]
_SupportsArray
只是一个带有 __array__
方法的协议(protocol)。它既不需要实现 __len__
(与 len
函数一起使用),也不需要实现 __getitem__
(用于索引)。
_NestedSequence
是一个限制性更强的协议(protocol),确实实际上需要 __len__
和 __getitem__
。
但是这段代码的问题是,参数注解是union:
import numpy.typing as npt
...
def f(a: npt.ArrayLike) -> int:
return len(a)
所以a
可能是一个支持__len__
的类似序列的对象,但它也可能只是一个仅支持 __array__ 的对象。例如,它甚至可能只是一个 int
(再次参见联合)。因此,调用 len(a)
是不安全的。
同样,这里的项目访问不是类型安全的,因为 a
可能不会实现 __getitem__
:
...
def g(a: npt.ArrayLike) -> Any:
return a[0]
所以它对你不起作用的原因是它不意味着用作 numpy 数组或其他序列的注释;它旨在用于可以转换为 numpy 数组的东西。
如果您想注释函数 f
和 g
以同时获取列表和 numpy 数组,您可以只使用 list
的并集和 NDArray
就像 list[Any] | npt.NDArray[任意]
.
如果您想要更宽的注释来容纳任何具有 __len__
和 __getitem__
的类型,您需要定义自己的 protocol :
from typing import Any, Protocol, TypeVar
import numpy as np
T = TypeVar("T", covariant=True)
class SequenceLike(Protocol[T]):
def __len__(self) -> int: ...
def __getitem__(self, item: int) -> T: ...
def f(a: SequenceLike[Any]) -> int:
return len(a)
def g(a: SequenceLike[T]) -> T:
return a[0]
print(f(np.array([0, 1])), g(np.array([0, 1])))
print(f([0, 1]), g([0, 1]))
更准确地说,__getitem__
可能还应该采用 slice
对象,但重载对您来说可能有点过分了。
关于python - 使用 ArrayLike 时出现 Mypy 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76270706/