Typing (numpy.typing)#

新功能,版本 1.20。

NumPy API 的大部分内容都带有 PEP 484 风格的类型注解。此外,还为用户提供了一些类型别名,其中最突出的是以下两个:

Mypy 插件#

新功能,版本 1.21。

一个用于管理许多平台特定注解的 mypy 插件。其功能可分为三个独立的部分:

  • 分配某些 number 子类的(平台相关)精度,包括 int_intplonglong 等。有关受影响类的全面概述,请参阅有关 标量类型 的文档。没有此插件,所有相关类的精度都将被推断为 Any

  • 删除所有在所讨论平台上不可用的扩展精度 number 子类。最值得注意的是 float128complex256 等。没有此插件,对于 mypy 而言,*所有* 扩展精度类型都将可用于所有平台。

  • 分配(平台相关)的 `c_intp` 精度。没有此插件,该类型将默认为 ctypes.c_int64

    新功能,版本 1.22。

已弃用,版本 2.3:`numpy.typing.mypy_plugin` 入口点已弃用,取而代之的是平台无关的静态类型推断。请从 mypy 配置的 `plugins` 部分中删除 `numpy.typing.mypy_plugin`;如果这会暴露新的错误,请提供一个最小的可重现示例来打开一个 issue。

示例#

要启用该插件,必须将其添加到 mypy 的 配置文件中。

[mypy]
plugins = numpy.typing.mypy_plugin

与运行时 NumPy API 的区别#

NumPy 非常灵活。静态描述所有可能性将导致类型非常无用。因此,带类型的 NumPy API 通常比运行时 NumPy API 更严格。本节介绍一些值得注意的区别。

ArrayLike#

`ArrayLike` 类型试图避免创建对象数组。例如:

>>> np.array(x**2 for x in range(10))
array(<generator object <genexpr> at ...>, dtype=object)

是有效的 NumPy 代码,它将创建一个 0 维对象数组。然而,在使用 NumPy 类型时,类型检查器会抱怨上述示例。如果您确实打算这样做,则可以使用 `# type: ignore` 注释

>>> np.array(x**2 for x in range(10))  # type: ignore

或者将数组对象显式类型化为 Any

>>> from typing import Any
>>> array_like: Any = (x**2 for x in range(10))
>>> np.array(array_like)
array(<generator object <genexpr> at ...>, dtype=object)

ndarray#

可以在运行时修改数组的 dtype。例如,以下代码是有效的:

>>> x = np.array([1, 2])
>>> x.dtype = np.bool

这种变异不允许通过类型。想要编写静态类型代码的用户应改用 `numpy.ndarray.view` 方法来创建具有不同 dtype 的数组视图。

DTypeLike#

`DTypeLike` 类型试图避免使用如下字段字典创建 dtype 对象:

>>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)})

虽然这是有效的 NumPy 代码,但类型检查器会抱怨它,因为不鼓励使用它。请参阅: 数据类型对象

数字精度#

`numpy.number` 子类的精度被视为不变的泛型参数(参见 NBitBase),从而简化了涉及基于精度的转换的注解。

>>> from typing import TypeVar
>>> import numpy as np
>>> import numpy.typing as npt

>>> T = TypeVar("T", bound=npt.NBitBase)
>>> def func(a: np.floating[T], b: np.floating[T]) -> np.floating[T]:
...     ...

因此,`float16`、`float32` 和 `float64` 等仍然是 `floating` 的子类型,但与运行时不同,它们不一定被视为子类。

已弃用,版本 2.3:`NBitBase` 辅助函数已弃用,将在未来版本中删除。请改用 `typing.overload` 或以具体标量类为上限的 `TypeVar` 定义来表示精度关系。例如:

from typing import TypeVar
import numpy as np

S = TypeVar("S", bound=np.floating)

def func(a: S, b: S) -> S:
    ...

或者,在不同的输入类型映射到不同的输出类型的情况下:

from typing import overload
import numpy as np

@overload
def phase(x: np.complex64) -> np.float32: ...
@overload
def phase(x: np.complex128) -> np.float64: ...
@overload
def phase(x: np.clongdouble) -> np.longdouble: ...
def phase(x: np.complexfloating) -> np.floating:
    ...

Timedelta64#

`timedelta64` 类不被视为 `signedinteger` 的子类,而在静态类型检查时,前者仅继承自 `generic`。

0D 数组#

在运行时,numpy 会积极地将任何传入的 0D 数组强制转换为其相应的 `generic` 实例。在形状类型化(参见 PEP 646)的引入之前,不幸的是无法区分 0D 和 >0D 数组。因此,虽然不严格正确,但所有可能执行 0D 数组 -> 标量转换的操作目前都被注解为仅返回 `ndarray`。

如果提前知道某个操作*将*执行 0D 数组 -> 标量转换,则可以考虑使用 `typing.cast` 或 `# type: ignore` 注释来手动纠正这种情况。

记录数组 dtype#

`numpy.recarray` 的 dtype,以及通常的 `Creating record arrays` 函数,可以通过以下两种方式之一指定:

  • 直接通过 `dtype` 参数。

  • 通过 `numpy.rec.format_parser` 使用最多五个辅助参数:`formats`、`names`、`titles`、`aligned` 和 `byteorder`。

这两种方法目前被类型化为互斥的,*即*如果指定了 `dtype`,则不能指定 `formats`。虽然运行时不(严格)强制执行这种互斥性,但结合使用这两种 dtype 说明符可能会导致意外甚至错误的行为。

API#

numpy.typing.ArrayLike = typing.Union[...]#

一个代表可以强制转换为 `ndarray` 的对象的 `Union`。

其中,包括以下内容:

  • 标量。

  • (嵌套)序列。

  • 实现了 `__array__` 协议的对象。

新功能,版本 1.20。

另请参阅

array_like:

任何可以解释为 ndarray 的标量或序列。

示例

>>> import numpy as np
>>> import numpy.typing as npt

>>> def as_array(a: npt.ArrayLike) -> np.ndarray:
...     return np.array(a)
numpy.typing.DTypeLike = typing.Union[...]#

一个代表可以强制转换为 `dtype` 的对象的 `Union`。

其中,包括以下内容:

  • 类型对象。

  • 字符代码或类型对象的名称。

  • 具有 `.dtype` 属性的对象。

新功能,版本 1.20。

另请参阅

指定和构造数据类型

所有可以强制转换为数据类型的对象的全面概述。

示例

>>> import numpy as np
>>> import numpy.typing as npt

>>> def as_dtype(d: npt.DTypeLike) -> np.dtype:
...     return np.dtype(d)
numpy.typing.NDArray = numpy.ndarray[tuple[typing.Any, ...], numpy.dtype[~_ScalarT]]#

一个 `np.ndarray[tuple[Any, ...], np.dtype[ScalarT]]` 类型别名,就其 `dtype.type` 而言,这是一个 泛型

可在运行时用于键入具有给定 dtype 和未指定形状的数组。

新功能,版本 1.21。

示例

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[tuple[typing.Any, ...], numpy.dtype[~_ScalarT]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[tuple[typing.Any, ...], numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
...     return np.array(a)
class numpy.typing.NBitBase[source]#

一个在静态类型检查期间表示 `numpy.number` 精度的类型。

仅用于静态类型检查的目的,`NBitBase` 代表一系列子类的层次结构。每个后续子类在此用于表示较低级别的精度,*例如* `64Bit > 32Bit > 16Bit`。

新功能,版本 1.20。

已弃用,版本 2.3:请改用 `@typing.overload` 或以标量类型作为上限的 `TypeVar`。

示例

以下是一个典型的用法示例:`NBitBase` 在此用于注解一个函数,该函数接受任意精度的浮点数和整数作为参数,并返回具有最大精度的任何新浮点数(*例如* `np.float16 + np.int64 -> np.float64`)。

>>> from typing import TypeVar, TYPE_CHECKING
>>> import numpy as np
>>> import numpy.typing as npt

>>> S = TypeVar("S", bound=npt.NBitBase)
>>> T = TypeVar("T", bound=npt.NBitBase)

>>> def add(a: np.floating[S], b: np.integer[T]) -> np.floating[S | T]:
...     return a + b

>>> a = np.float16()
>>> b = np.int64()
>>> out = add(a, b)

>>> if TYPE_CHECKING:
...     reveal_locals()
...     # note: Revealed local types are:
...     # note:     a: numpy.floating[numpy.typing._16Bit*]
...     # note:     b: numpy.signedinteger[numpy.typing._64Bit*]
...     # note:     out: numpy.floating[numpy.typing._64Bit*]