Типизация (numpy.typing)#

Новое в версии 1.20.

Большие части API NumPy имеют PEP 484-стилевые аннотации типов. Кроме того, пользователям доступен ряд псевдонимов типов, наиболее заметные из которых приведены ниже:

  • ArrayLike: объекты, которые можно преобразовать в массивы

  • DTypeLike: объекты, которые можно преобразовать в dtypes

Mypy plugin#

Новое в версии 1.21.

A mypy плагин для управления несколькими платформенно-специфичными аннотациями. Его функциональность можно разделить на три отдельные части:

  • Назначение (зависящих от платформы) точностей определённых number подклассы, включая такие как int_, intp и longlong. См. документацию по скалярные типы для полного обзора затронутых классов. Без плагина точность всех соответствующих классов будет выведена как Any.

  • Удаление всей расширенной точности number подклассы, которые недоступны для рассматриваемой платформы. Наиболее заметно это включает такие классы, как float128 и complex256. Без плагина все расширенные типы точности будут, насколько это касается mypy, доступны на всех платформах.

  • Назначение (зависимой от платформы) точности c_intp. Без плагина тип по умолчанию будет ctypes.c_int64.

    Добавлено в версии 1.22.

Устарело с версии 2.3: The numpy.typing.mypy_plugin точка входа устарела в пользу независимой от платформы статической проверки типов. Удалить numpy.typing.mypy_plugin из plugins раздел вашей конфигурации mypy; если это выявит новые ошибки, пожалуйста, откройте issue с минимальным воспроизводимым примером.

Примеры#

Чтобы включить плагин, необходимо добавить его в свой mypy файл конфигурации:

[mypy]
plugins = numpy.typing.mypy_plugin

Отличия от API NumPy во время выполнения#

NumPy очень гибок. Попытка статически описать весь диапазон возможностей привела бы к типам, которые не очень полезны. По этой причине типизированный API NumPy часто строже, чем API NumPy во время выполнения. В этом разделе описаны некоторые заметные различия.

ArrayLike#

The ArrayLike тип пытается избежать создания массивов объектов. Например,

>>> np.array(x**2 for x in range(10))
array( 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( at ...>, dtype=object)

ndarray#

Возможно изменять dtype массива во время выполнения. Например, следующий код является допустимым:

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

Такой вид мутации не разрешён типами. Пользователи, которые хотят писать статически типизированный код, должны вместо этого использовать numpy.ndarray.view метод для создания представления массива с другим dtype.

DTypeLike#

The DTypeLike тип пытается избежать создания объектов dtype с использованием словаря полей, как показано ниже:

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

Хотя это допустимый код NumPy, проверка типов будет жаловаться на него, так как его использование не рекомендуется. Пожалуйста, смотрите : Объекты типов данных

Вклад в 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: The 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#

The timedelta64 класс не считается подклассом signedinteger, причём первый наследует только от generic при статической проверке типов.

0D массивы#

Во время выполнения numpy агрессивно преобразует любые переданные 0D массивы в их соответствующие generic экземпляр. До введения типизации формы (см. PEP 646) к сожалению невозможно сделать необходимое различие между 0D и >0D массивами. Хотя это не строго корректно, все операции, которые потенциально могут выполнить приведение 0D-массива -> скаляра, в настоящее время аннотированы как возвращающие исключительно ndarray.

Если заранее известно, что операция будет выполнить преобразование 0D-массива -> скаляр, тогда можно вручную исправить ситуацию с помощью typing.cast или # type: ignore комментарий.

Типы данных записей массивов#

Тип данных numpy.recarrayдолжны быть включены в старые категории. Значения, которые были в удаленных категориях, будут установлены в NaN Создание массивов записей функции в целом могут быть указаны одним из двух способов:

  • Напрямую через dtype аргумент.

  • С помощью до пяти вспомогательных аргументов, которые работают через numpy.rec.format_parser: formats, names, titles, aligned и byteorder.

Эти два подхода в настоящее время типизированы как взаимоисключающие, т.е. if dtype указано, то нельзя указывать formats. Хотя эта взаимоисключительность не (строго) применяется во время выполнения, комбинирование обоих спецификаторов типов данных может привести к неожиданному или даже ошибочному поведению.

API#

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

A Union представляющий объекты, которые могут быть приведены к ndarray.

Среди прочего это включает такие вещи, как:

  • Скаляры.

  • (Вложенные) последовательности.

  • Объекты, реализующие __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[...]#

A Union представляющие объекты, которые могут быть приведены к dtype.

Среди прочего это включает такие вещи, как:

  • type объекты.

  • Символьные коды или имена type объекты.

  • Объекты с .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]]#

A 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)
класс numpy.typing.NBitBase[источник]#

Тип, представляющий numpy.number точность во время статической проверки типов.

Используется исключительно для статической проверки типов, NBitBase представляет основу иерархического набора подклассов. Каждый последующий подкласс используется для представления более низкого уровня точности, например, 64Bit > 32Bit > 16Bit.

Новое в версии 1.20.

Устарело с версии 2.3: Используйте @typing.overload или TypeVar со скалярным типом в качестве верхней границы, вместо этого.

Примеры

Ниже приведен типичный пример использования: NBitBase здесь используется для аннотации функции, которая принимает float и целое число произвольной точности в качестве аргументов и возвращает новый float с наибольшей точностью (например, 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*]