__init__.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. Differences from the runtime NumPy API
  17. --------------------------------------
  18. NumPy is very flexible. Trying to describe the full range of
  19. possibilities statically would result in types that are not very
  20. helpful. For that reason, the typed NumPy API is often stricter than
  21. the runtime NumPy API. This section describes some notable
  22. differences.
  23. ArrayLike
  24. ~~~~~~~~~
  25. The `ArrayLike` type tries to avoid creating object arrays. For
  26. example,
  27. .. code-block:: python
  28. >>> np.array(x**2 for x in range(10))
  29. array(<generator object <genexpr> at ...>, dtype=object)
  30. is valid NumPy code which will create a 0-dimensional object
  31. array. Type checkers will complain about the above example when using
  32. the NumPy types however. If you really intended to do the above, then
  33. you can either use a ``# type: ignore`` comment:
  34. .. code-block:: python
  35. >>> np.array(x**2 for x in range(10)) # type: ignore
  36. or explicitly type the array like object as `~typing.Any`:
  37. .. code-block:: python
  38. >>> from typing import Any
  39. >>> array_like: Any = (x**2 for x in range(10))
  40. >>> np.array(array_like)
  41. array(<generator object <genexpr> at ...>, dtype=object)
  42. ndarray
  43. ~~~~~~~
  44. It's possible to mutate the dtype of an array at runtime. For example,
  45. the following code is valid:
  46. .. code-block:: python
  47. >>> x = np.array([1, 2])
  48. >>> x.dtype = np.bool_
  49. This sort of mutation is not allowed by the types. Users who want to
  50. write statically typed code should insted use the `numpy.ndarray.view`
  51. method to create a view of the array with a different dtype.
  52. DTypeLike
  53. ~~~~~~~~~
  54. The `DTypeLike` type tries to avoid creation of dtype objects using
  55. dictionary of fields like below:
  56. .. code-block:: python
  57. >>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)})
  58. Although this is valid Numpy code, the type checker will complain about it,
  59. since its usage is discouraged.
  60. Please see : :ref:`Data type objects <arrays.dtypes>`
  61. Number Precision
  62. ~~~~~~~~~~~~~~~~
  63. The precision of `numpy.number` subclasses is treated as a covariant generic
  64. parameter (see :class:`~NBitBase`), simplifying the annoting of proccesses
  65. involving precision-based casting.
  66. .. code-block:: python
  67. >>> from typing import TypeVar
  68. >>> import numpy as np
  69. >>> import numpy.typing as npt
  70. >>> T = TypeVar("T", bound=npt.NBitBase)
  71. >>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
  72. ... ...
  73. Consequently, the likes of `~numpy.float16`, `~numpy.float32` and
  74. `~numpy.float64` are still sub-types of `~numpy.floating`, but, contrary to
  75. runtime, they're not necessarily considered as sub-classes.
  76. Timedelta64
  77. ~~~~~~~~~~~
  78. The `~numpy.timedelta64` class is not considered a subclass of `~numpy.signedinteger`,
  79. the former only inheriting from `~numpy.generic` while static type checking.
  80. API
  81. ---
  82. """
  83. # NOTE: The API section will be appended with additional entries
  84. # further down in this file
  85. from typing import TYPE_CHECKING, List
  86. if TYPE_CHECKING:
  87. import sys
  88. if sys.version_info >= (3, 8):
  89. from typing import final
  90. else:
  91. from typing_extensions import final
  92. else:
  93. def final(f): return f
  94. if not TYPE_CHECKING:
  95. __all__ = ["ArrayLike", "DTypeLike", "NBitBase"]
  96. else:
  97. # Ensure that all objects within this module are accessible while
  98. # static type checking. This includes private ones, as we need them
  99. # for internal use.
  100. #
  101. # Declare to mypy that `__all__` is a list of strings without assigning
  102. # an explicit value
  103. __all__: List[str]
  104. @final # Dissallow the creation of arbitrary `NBitBase` subclasses
  105. class NBitBase:
  106. """
  107. An object representing `numpy.number` precision during static type checking.
  108. Used exclusively for the purpose static type checking, `NBitBase`
  109. represents the base of a hierachieral set of subclasses.
  110. Each subsequent subclass is herein used for representing a lower level
  111. of precision, *e.g.* ``64Bit > 32Bit > 16Bit``.
  112. Examples
  113. --------
  114. Below is a typical usage example: `NBitBase` is herein used for annotating a
  115. function that takes a float and integer of arbitrary precision as arguments
  116. and returns a new float of whichever precision is largest
  117. (*e.g.* ``np.float16 + np.int64 -> np.float64``).
  118. .. code-block:: python
  119. >>> from typing import TypeVar, TYPE_CHECKING
  120. >>> import numpy as np
  121. >>> import numpy.typing as npt
  122. >>> T = TypeVar("T", bound=npt.NBitBase)
  123. >>> def add(a: "np.floating[T]", b: "np.integer[T]") -> "np.floating[T]":
  124. ... return a + b
  125. >>> a = np.float16()
  126. >>> b = np.int64()
  127. >>> out = add(a, b)
  128. >>> if TYPE_CHECKING:
  129. ... reveal_locals()
  130. ... # note: Revealed local types are:
  131. ... # note: a: numpy.floating[numpy.typing._16Bit*]
  132. ... # note: b: numpy.signedinteger[numpy.typing._64Bit*]
  133. ... # note: out: numpy.floating[numpy.typing._64Bit*]
  134. """
  135. def __init_subclass__(cls) -> None:
  136. allowed_names = {
  137. "NBitBase", "_256Bit", "_128Bit", "_96Bit", "_80Bit",
  138. "_64Bit", "_32Bit", "_16Bit", "_8Bit",
  139. }
  140. if cls.__name__ not in allowed_names:
  141. raise TypeError('cannot inherit from final class "NBitBase"')
  142. super().__init_subclass__()
  143. # Silence errors about subclassing a `@final`-decorated class
  144. class _256Bit(NBitBase): ... # type: ignore[misc]
  145. class _128Bit(_256Bit): ... # type: ignore[misc]
  146. class _96Bit(_128Bit): ... # type: ignore[misc]
  147. class _80Bit(_96Bit): ... # type: ignore[misc]
  148. class _64Bit(_80Bit): ... # type: ignore[misc]
  149. class _32Bit(_64Bit): ... # type: ignore[misc]
  150. class _16Bit(_32Bit): ... # type: ignore[misc]
  151. class _8Bit(_16Bit): ... # type: ignore[misc]
  152. # Clean up the namespace
  153. del TYPE_CHECKING, final, List
  154. from ._scalars import (
  155. _CharLike,
  156. _BoolLike,
  157. _IntLike,
  158. _FloatLike,
  159. _ComplexLike,
  160. _NumberLike,
  161. _ScalarLike,
  162. _VoidLike,
  163. )
  164. from ._array_like import _SupportsArray, ArrayLike as ArrayLike
  165. from ._shape import _Shape, _ShapeLike
  166. from ._dtype_like import _SupportsDType, _VoidDTypeLike, DTypeLike as DTypeLike
  167. if __doc__ is not None:
  168. from ._add_docstring import _docstrings
  169. __doc__ += _docstrings
  170. __doc__ += '\n.. autoclass:: numpy.typing.NBitBase\n'
  171. del _docstrings
  172. from numpy._pytesttester import PytestTester
  173. test = PytestTester(__name__)
  174. del PytestTester