图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
11 KiB

  1. """
  2. ============================
  3. Typing (:mod:`numpy.typing`)
  4. ============================
  5. .. warning::
  6. Some of the types in this module rely on features only present in
  7. the standard library in Python 3.8 and greater. If you want to use
  8. these types in earlier versions of Python, you should install the
  9. typing-extensions_ package.
  10. Large parts of the NumPy API have PEP-484-style type annotations. In
  11. addition a number of type aliases are available to users, most prominently
  12. the two below:
  13. - `ArrayLike`: objects that can be converted to arrays
  14. - `DTypeLike`: objects that can be converted to dtypes
  15. .. _typing-extensions: https://pypi.org/project/typing-extensions/
  16. Mypy plugin
  17. -----------
  18. A mypy_ plugin is distributed in `numpy.typing` for managing a number of
  19. platform-specific annotations. Its function can be split into to parts:
  20. * Assigning the (platform-dependent) precisions of certain `~numpy.number` subclasses,
  21. including the likes of `~numpy.int_`, `~numpy.intp` and `~numpy.longlong`.
  22. See the documentation on :ref:`scalar types <arrays.scalars.built-in>` for a
  23. comprehensive overview of the affected classes. without the plugin the precision
  24. of all relevant classes will be inferred as `~typing.Any`.
  25. * Removing all extended-precision `~numpy.number` subclasses that are unavailable
  26. for the platform in question. Most notable this includes the likes of
  27. `~numpy.float128` and `~numpy.complex256`. Without the plugin *all*
  28. extended-precision types will, as far as mypy is concerned, be available
  29. to all platforms.
  30. To enable the plugin, one must add it to their mypy `configuration file`_:
  31. .. code-block:: ini
  32. [mypy]
  33. plugins = numpy.typing.mypy_plugin
  34. .. _mypy: http://mypy-lang.org/
  35. .. _configuration file: https://mypy.readthedocs.io/en/stable/config_file.html
  36. Differences from the runtime NumPy API
  37. --------------------------------------
  38. NumPy is very flexible. Trying to describe the full range of
  39. possibilities statically would result in types that are not very
  40. helpful. For that reason, the typed NumPy API is often stricter than
  41. the runtime NumPy API. This section describes some notable
  42. differences.
  43. ArrayLike
  44. ~~~~~~~~~
  45. The `ArrayLike` type tries to avoid creating object arrays. For
  46. example,
  47. .. code-block:: python
  48. >>> np.array(x**2 for x in range(10))
  49. array(<generator object <genexpr> at ...>, dtype=object)
  50. is valid NumPy code which will create a 0-dimensional object
  51. array. Type checkers will complain about the above example when using
  52. the NumPy types however. If you really intended to do the above, then
  53. you can either use a ``# type: ignore`` comment:
  54. .. code-block:: python
  55. >>> np.array(x**2 for x in range(10)) # type: ignore
  56. or explicitly type the array like object as `~typing.Any`:
  57. .. code-block:: python
  58. >>> from typing import Any
  59. >>> array_like: Any = (x**2 for x in range(10))
  60. >>> np.array(array_like)
  61. array(<generator object <genexpr> at ...>, dtype=object)
  62. ndarray
  63. ~~~~~~~
  64. It's possible to mutate the dtype of an array at runtime. For example,
  65. the following code is valid:
  66. .. code-block:: python
  67. >>> x = np.array([1, 2])
  68. >>> x.dtype = np.bool_
  69. This sort of mutation is not allowed by the types. Users who want to
  70. write statically typed code should instead use the `numpy.ndarray.view`
  71. method to create a view of the array with a different dtype.
  72. DTypeLike
  73. ~~~~~~~~~
  74. The `DTypeLike` type tries to avoid creation of dtype objects using
  75. dictionary of fields like below:
  76. .. code-block:: python
  77. >>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)})
  78. Although this is valid NumPy code, the type checker will complain about it,
  79. since its usage is discouraged.
  80. Please see : :ref:`Data type objects <arrays.dtypes>`
  81. Number precision
  82. ~~~~~~~~~~~~~~~~
  83. The precision of `numpy.number` subclasses is treated as a covariant generic
  84. parameter (see :class:`~NBitBase`), simplifying the annotating of processes
  85. involving precision-based casting.
  86. .. code-block:: python
  87. >>> from typing import TypeVar
  88. >>> import numpy as np
  89. >>> import numpy.typing as npt
  90. >>> T = TypeVar("T", bound=npt.NBitBase)
  91. >>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
  92. ... ...
  93. Consequently, the likes of `~numpy.float16`, `~numpy.float32` and
  94. `~numpy.float64` are still sub-types of `~numpy.floating`, but, contrary to
  95. runtime, they're not necessarily considered as sub-classes.
  96. Timedelta64
  97. ~~~~~~~~~~~
  98. The `~numpy.timedelta64` class is not considered a subclass of `~numpy.signedinteger`,
  99. the former only inheriting from `~numpy.generic` while static type checking.
  100. 0D arrays
  101. ~~~~~~~~~
  102. During runtime numpy aggressively casts any passed 0D arrays into their
  103. corresponding `~numpy.generic` instance. Until the introduction of shape
  104. typing (see :pep:`646`) it is unfortunately not possible to make the
  105. necessary distinction between 0D and >0D arrays. While thus not strictly
  106. correct, all operations are that can potentially perform a 0D-array -> scalar
  107. cast are currently annotated as exclusively returning an `ndarray`.
  108. If it is known in advance that an operation _will_ perform a
  109. 0D-array -> scalar cast, then one can consider manually remedying the
  110. situation with either `typing.cast` or a ``# type: ignore`` comment.
  111. API
  112. ---
  113. """
  114. # NOTE: The API section will be appended with additional entries
  115. # further down in this file
  116. from numpy import ufunc
  117. from typing import TYPE_CHECKING, List
  118. if TYPE_CHECKING:
  119. import sys
  120. if sys.version_info >= (3, 8):
  121. from typing import final
  122. else:
  123. from typing_extensions import final
  124. else:
  125. def final(f): return f
  126. if not TYPE_CHECKING:
  127. __all__ = ["ArrayLike", "DTypeLike", "NBitBase", "NDArray"]
  128. else:
  129. # Ensure that all objects within this module are accessible while
  130. # static type checking. This includes private ones, as we need them
  131. # for internal use.
  132. #
  133. # Declare to mypy that `__all__` is a list of strings without assigning
  134. # an explicit value
  135. __all__: List[str]
  136. @final # Dissallow the creation of arbitrary `NBitBase` subclasses
  137. class NBitBase:
  138. """
  139. An object representing `numpy.number` precision during static type checking.
  140. Used exclusively for the purpose static type checking, `NBitBase`
  141. represents the base of a hierarchical set of subclasses.
  142. Each subsequent subclass is herein used for representing a lower level
  143. of precision, *e.g.* ``64Bit > 32Bit > 16Bit``.
  144. Examples
  145. --------
  146. Below is a typical usage example: `NBitBase` is herein used for annotating a
  147. function that takes a float and integer of arbitrary precision as arguments
  148. and returns a new float of whichever precision is largest
  149. (*e.g.* ``np.float16 + np.int64 -> np.float64``).
  150. .. code-block:: python
  151. >>> from __future__ import annotations
  152. >>> from typing import TypeVar, Union, TYPE_CHECKING
  153. >>> import numpy as np
  154. >>> import numpy.typing as npt
  155. >>> T1 = TypeVar("T1", bound=npt.NBitBase)
  156. >>> T2 = TypeVar("T2", bound=npt.NBitBase)
  157. >>> def add(a: np.floating[T1], b: np.integer[T2]) -> np.floating[Union[T1, T2]]:
  158. ... return a + b
  159. >>> a = np.float16()
  160. >>> b = np.int64()
  161. >>> out = add(a, b)
  162. >>> if TYPE_CHECKING:
  163. ... reveal_locals()
  164. ... # note: Revealed local types are:
  165. ... # note: a: numpy.floating[numpy.typing._16Bit*]
  166. ... # note: b: numpy.signedinteger[numpy.typing._64Bit*]
  167. ... # note: out: numpy.floating[numpy.typing._64Bit*]
  168. """
  169. def __init_subclass__(cls) -> None:
  170. allowed_names = {
  171. "NBitBase", "_256Bit", "_128Bit", "_96Bit", "_80Bit",
  172. "_64Bit", "_32Bit", "_16Bit", "_8Bit",
  173. }
  174. if cls.__name__ not in allowed_names:
  175. raise TypeError('cannot inherit from final class "NBitBase"')
  176. super().__init_subclass__()
  177. # Silence errors about subclassing a `@final`-decorated class
  178. class _256Bit(NBitBase): ... # type: ignore[misc]
  179. class _128Bit(_256Bit): ... # type: ignore[misc]
  180. class _96Bit(_128Bit): ... # type: ignore[misc]
  181. class _80Bit(_96Bit): ... # type: ignore[misc]
  182. class _64Bit(_80Bit): ... # type: ignore[misc]
  183. class _32Bit(_64Bit): ... # type: ignore[misc]
  184. class _16Bit(_32Bit): ... # type: ignore[misc]
  185. class _8Bit(_16Bit): ... # type: ignore[misc]
  186. from ._nbit import (
  187. _NBitByte,
  188. _NBitShort,
  189. _NBitIntC,
  190. _NBitIntP,
  191. _NBitInt,
  192. _NBitLongLong,
  193. _NBitHalf,
  194. _NBitSingle,
  195. _NBitDouble,
  196. _NBitLongDouble,
  197. )
  198. from ._char_codes import (
  199. _BoolCodes,
  200. _UInt8Codes,
  201. _UInt16Codes,
  202. _UInt32Codes,
  203. _UInt64Codes,
  204. _Int8Codes,
  205. _Int16Codes,
  206. _Int32Codes,
  207. _Int64Codes,
  208. _Float16Codes,
  209. _Float32Codes,
  210. _Float64Codes,
  211. _Complex64Codes,
  212. _Complex128Codes,
  213. _ByteCodes,
  214. _ShortCodes,
  215. _IntCCodes,
  216. _IntPCodes,
  217. _IntCodes,
  218. _LongLongCodes,
  219. _UByteCodes,
  220. _UShortCodes,
  221. _UIntCCodes,
  222. _UIntPCodes,
  223. _UIntCodes,
  224. _ULongLongCodes,
  225. _HalfCodes,
  226. _SingleCodes,
  227. _DoubleCodes,
  228. _LongDoubleCodes,
  229. _CSingleCodes,
  230. _CDoubleCodes,
  231. _CLongDoubleCodes,
  232. _DT64Codes,
  233. _TD64Codes,
  234. _StrCodes,
  235. _BytesCodes,
  236. _VoidCodes,
  237. _ObjectCodes,
  238. )
  239. from ._scalars import (
  240. _CharLike_co,
  241. _BoolLike_co,
  242. _UIntLike_co,
  243. _IntLike_co,
  244. _FloatLike_co,
  245. _ComplexLike_co,
  246. _TD64Like_co,
  247. _NumberLike_co,
  248. _ScalarLike_co,
  249. _VoidLike_co,
  250. )
  251. from ._shape import _Shape, _ShapeLike
  252. from ._dtype_like import (
  253. DTypeLike as DTypeLike,
  254. _SupportsDType,
  255. _VoidDTypeLike,
  256. _DTypeLikeBool,
  257. _DTypeLikeUInt,
  258. _DTypeLikeInt,
  259. _DTypeLikeFloat,
  260. _DTypeLikeComplex,
  261. _DTypeLikeTD64,
  262. _DTypeLikeDT64,
  263. _DTypeLikeObject,
  264. _DTypeLikeVoid,
  265. _DTypeLikeStr,
  266. _DTypeLikeBytes,
  267. _DTypeLikeComplex_co,
  268. )
  269. from ._array_like import (
  270. ArrayLike as ArrayLike,
  271. _ArrayLike,
  272. _NestedSequence,
  273. _RecursiveSequence,
  274. _SupportsArray,
  275. _ArrayLikeInt,
  276. _ArrayLikeBool_co,
  277. _ArrayLikeUInt_co,
  278. _ArrayLikeInt_co,
  279. _ArrayLikeFloat_co,
  280. _ArrayLikeComplex_co,
  281. _ArrayLikeNumber_co,
  282. _ArrayLikeTD64_co,
  283. _ArrayLikeDT64_co,
  284. _ArrayLikeObject_co,
  285. _ArrayLikeVoid_co,
  286. _ArrayLikeStr_co,
  287. _ArrayLikeBytes_co,
  288. )
  289. from ._generic_alias import (
  290. NDArray as NDArray,
  291. _GenericAlias,
  292. )
  293. if TYPE_CHECKING:
  294. from ._ufunc import (
  295. _UFunc_Nin1_Nout1,
  296. _UFunc_Nin2_Nout1,
  297. _UFunc_Nin1_Nout2,
  298. _UFunc_Nin2_Nout2,
  299. _GUFunc_Nin2_Nout1,
  300. )
  301. else:
  302. # Declare the (type-check-only) ufunc subclasses as ufunc aliases during
  303. # runtime; this helps autocompletion tools such as Jedi (numpy/numpy#19834)
  304. _UFunc_Nin1_Nout1 = ufunc
  305. _UFunc_Nin2_Nout1 = ufunc
  306. _UFunc_Nin1_Nout2 = ufunc
  307. _UFunc_Nin2_Nout2 = ufunc
  308. _GUFunc_Nin2_Nout1 = ufunc
  309. # Clean up the namespace
  310. del TYPE_CHECKING, final, List, ufunc
  311. if __doc__ is not None:
  312. from ._add_docstring import _docstrings
  313. __doc__ += _docstrings
  314. __doc__ += '\n.. autoclass:: numpy.typing.NBitBase\n'
  315. del _docstrings
  316. from numpy._pytesttester import PytestTester
  317. test = PytestTester(__name__)
  318. del PytestTester