diff options
author | Marten van Kerkwijk <mhvk@astro.utoronto.ca> | 2017-03-14 18:27:33 -0400 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2017-04-27 13:25:49 -0600 |
commit | 6a3ca31530b67c91742240c0b8ee59903f4ec49f (patch) | |
tree | 91aea796c3be78c6436c7e8203efb19ff6d2b927 /doc/source/reference/arrays.classes.rst | |
parent | 3124e9692aa7cc1aa3baf1f148291bd9ed00d7fd (diff) | |
download | numpy-6a3ca31530b67c91742240c0b8ee59903f4ec49f.tar.gz |
DOC: describe current implementation of __array_ufunc__.
Diffstat (limited to 'doc/source/reference/arrays.classes.rst')
-rw-r--r-- | doc/source/reference/arrays.classes.rst | 98 |
1 files changed, 50 insertions, 48 deletions
diff --git a/doc/source/reference/arrays.classes.rst b/doc/source/reference/arrays.classes.rst index b1fb95d91..9a6aeb893 100644 --- a/doc/source/reference/arrays.classes.rst +++ b/doc/source/reference/arrays.classes.rst @@ -39,74 +39,70 @@ Special attributes and methods NumPy provides several hooks that classes can customize: -.. method:: class.__array_ufunc__(ufunc, method, inputs, **kwargs) +.. method:: class.__array_ufunc__(ufunc, method, *inputs, **kwargs) - .. versionadded:: 1.11 + .. versionadded:: 1.13 - Any class (ndarray subclass or not) can define this method to - override behavior of NumPy's ufuncs. This works quite similarly to - Python's ``__mul__`` and other binary operation routines. + Any class (ndarray subclass or not) can define this method (or set it to + :obj:`None`) to override behavior of NumPy's ufuncs. This works quite + similarly to Python's ``__mul__`` and other binary operation routines. - *ufunc* is the ufunc object that was called. - *method* is a string indicating which Ufunc method was called (one of ``"__call__"``, ``"reduce"``, ``"reduceat"``, ``"accumulate"``, ``"outer"``, ``"inner"``). - - *inputs* is a tuple of the input arguments to the ``ufunc`` + - *inputs* is a tuple of the input arguments to the ``ufunc``. - *kwargs* is a dictionary containing the optional input arguments - of the ufunc. The ``out`` argument is always contained in - *kwargs*, if given. See the discussion in :ref:`ufuncs` for - details. + of the ufunc. If given, any ``out`` arguments, both positional + and keyword, are passed as a :obj:`tuple` in *kwargs*. See the + discussion in :ref:`ufuncs` for details. The method should return either the result of the operation, or - :obj:`NotImplemented` if the operation requested is not - implemented. + :obj:`NotImplemented` if the operation requested is not implemented. If one of the arguments has a :func:`__array_ufunc__` method, it is executed *instead* of the ufunc. If more than one of the input arguments implements :func:`__array_ufunc__`, they are tried in the order: subclasses before superclasses, otherwise left to right. The - first routine returning something else than :obj:`NotImplemented` + first routine returning something other than :obj:`NotImplemented` determines the result. If all of the :func:`__array_ufunc__` operations return :obj:`NotImplemented`, a :exc:`TypeError` is raised. - If an :class:`ndarray` subclass defines the :func:`__array_ufunc__` - method, this disables the :func:`__array_wrap__`, - :func:`__array_prepare__`, :data:`__array_priority__` mechanism - described below. - .. note:: In addition to ufuncs, :func:`__array_ufunc__` also - overrides the behavior of :func:`numpy.dot` even though it is - not an Ufunc. - - .. note:: If you also define right-hand binary operator override - methods (such as ``__rmul__``) or comparison operations (such as - ``__gt__``) in your class, they take precedence over the - :func:`__array_ufunc__` mechanism when resolving results of - binary operations (such as ``ndarray_obj * your_obj``). - - The technical special case is: ``ndarray.__mul__`` returns - ``NotImplemented`` if the other object is *not* a subclass of - :class:`ndarray`, and defines both ``__array_ufunc__`` and - ``__rmul__``. Similar exception applies for the other operations - than multiplication. - - In such a case, when computing a binary operation such as - ``ndarray_obj * your_obj``, your ``__array_ufunc__`` method - *will not* be called. Instead, the execution passes on to your - right-hand ``__rmul__`` operation, as per standard Python - operator override rules. - - Similar special case applies to *in-place operations*: If you - define ``__rmul__``, then ``ndarray_obj *= your_obj`` *will not* - call your ``__array_ufunc__`` implementation. Instead, the - default Python behavior ``ndarray_obj = ndarray_obj * your_obj`` - occurs. - - Note that the above discussion applies only to Python's builtin - binary operation mechanism. ``np.multiply(ndarray_obj, - your_obj)`` always calls only your ``__array_ufunc__``, as - expected. + overrides the behavior of :func:`numpy.dot` and :func:`numpy.matmul` + even though these are not ufuncs. + + Like with other methods in python, such as ``__hash__`` and + ``__iter__``, it is possible to indicate that your class does *not* + support ufuncs by setting ``__array_ufunc__ = None``. With this, + inside ufuncs, your class will be treated as if it returned + :obj:`NotImplemented` (which will lead to an :exc:`TypeError` + unless another class also provides a :func:`__array_ufunc__` method + which knows what to do with your class). + + The presence of :func:`__array_ufunc__` also influences how binary + and comparison operators are dealt with, such as ``__add__``, + ``__gt__``, etc. If it is not :obj:`None`, the assumption is that + your code can handle such operations via the ufunc mechanism, and + hence forward methods on :class:`ndarray` will call the ufuncs + unconditionally (i.e., even if your class has defined reverse + methods such as ``__radd__``, ``__le__``, etc.). If + ``__array_ufunc__ = None``, however, forward methods on + :class:`ndarray` will unconditionally return :obj:`NotImplemented`, + so that your reverse methods will get called. + + .. note:: If you subclass :class:`ndarray`, we strongly recommend + that you avoid confusion by neither setting + :func:`__array_ufunc__` to :obj:`None` (which seems to make no + sense for an array subclass), nor defining it and also defining + reverse methods (which will be called by ``CPython`` in + preference over the :class:`ndarray` forward methods). + + .. note:: If a class defines the :func:`__array_ufunc__` method, + this disables the :func:`__array_wrap__`, + :func:`__array_prepare__`, :data:`__array_priority__` mechanism + described below (which may eventually be deprecated). .. method:: class.__array_finalize__(obj) @@ -129,6 +125,9 @@ NumPy provides several hooks that classes can customize: the subclass and update metadata before returning the array to the ufunc for computation. + .. note:: It is hoped to eventually deprecate this method in favour of + :func:__array_ufunc__`. + .. method:: class.__array_wrap__(array, context=None) At the end of every :ref:`ufunc <ufuncs.output-type>`, this method @@ -148,6 +147,9 @@ NumPy provides several hooks that classes can customize: possibility for the Python type of the returned object. Subclasses inherit a default value of 0.0 for this attribute. + .. note:: It is hoped to eventually deprecate this attribute in favour + of :func:__array_ufunc__`. + .. method:: class.__array__([dtype]) If a class (ndarray subclass or not) having the :func:`__array__` |