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 版本新增。

範例#

若要啟用此外掛程式,必須將其新增至 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]":
...     ...

因此,float16float32float64 等仍然是 floating 的子類型,但是,與執行階段相反,它們不一定被視為子類別。

Timedelta64#

timedelta64 類別在靜態類型檢查時不被視為 signedinteger 的子類別,前者僅繼承自 generic

0D 陣列#

在執行階段,numpy 會積極地將任何傳遞的 0D 陣列轉換為其對應的 generic 實例。在引入形狀類型(請參閱 PEP 646)之前,遺憾的是無法在 0D 和 >0D 陣列之間做出必要的區分。雖然這樣做並不完全正確,但目前所有可能執行 0D 陣列 -> 純量轉換的操作都被註解為僅傳回 ndarray

如果事先知道某個操作執行 0D 陣列 -> 純量轉換,則可以考慮使用 typing.cast# type: ignore 註解手動補救這種情況。

Record array dtypes#

numpy.recarray 的 dtype,以及一般的 建立記錄陣列 函式,可以用兩種方式之一指定

  • 直接透過 dtype 引數。

  • 最多使用五個輔助引數,這些引數透過 numpy.rec.format_parser 運作:formatsnamestitlesalignedbyteorder

這兩種方法目前被類型化為互斥,如果指定了 dtype,則不得指定 formats。雖然在執行階段並未(嚴格)強制執行這種互斥性,但組合使用這兩種 dtype 指定符可能會導致意外甚至完全錯誤的行為。

API#

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

一個 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[...]#

一個 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[int, ...], numpy.dtype[+_ScalarType_co]][source]#

關於其 dtype.typenp.ndarray[tuple[int, ...], np.dtype[+ScalarType]] 類型別名 generic

可以在執行階段用於類型化具有給定 dtype 和未指定形狀的陣列。

1.21 版本新增。

範例

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

>>> print(npt.NDArray)
numpy.ndarray[tuple[int, ...], numpy.dtype[+_ScalarType_co]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[tuple[int, ...], 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 版本新增。

範例

以下是一個典型的使用範例:NBitBase 在此用於註解一個函式,該函式接受任意精度的浮點數和整數作為引數,並傳回一個新的浮點數,其精度是兩者中較大的(例如 np.float16 + np.int64 -> np.float64)。

>>> from __future__ import annotations
>>> 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*]