"Fossies" - the Fresh Open Source Software Archive

Member "numpy-1.16.4/numpy/lib/mixins.py" (22 Feb 2019, 7268 Bytes) of package /linux/misc/numpy-1.16.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "mixins.py" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.15.4_vs_1.16.0.

    1 """Mixin classes for custom array types that don't inherit from ndarray."""
    2 from __future__ import division, absolute_import, print_function
    3 
    4 import sys
    5 
    6 from numpy.core import umath as um
    7 
    8 # Nothing should be exposed in the top-level NumPy module.
    9 __all__ = []
   10 
   11 
   12 def _disables_array_ufunc(obj):
   13     """True when __array_ufunc__ is set to None."""
   14     try:
   15         return obj.__array_ufunc__ is None
   16     except AttributeError:
   17         return False
   18 
   19 
   20 def _binary_method(ufunc, name):
   21     """Implement a forward binary method with a ufunc, e.g., __add__."""
   22     def func(self, other):
   23         if _disables_array_ufunc(other):
   24             return NotImplemented
   25         return ufunc(self, other)
   26     func.__name__ = '__{}__'.format(name)
   27     return func
   28 
   29 
   30 def _reflected_binary_method(ufunc, name):
   31     """Implement a reflected binary method with a ufunc, e.g., __radd__."""
   32     def func(self, other):
   33         if _disables_array_ufunc(other):
   34             return NotImplemented
   35         return ufunc(other, self)
   36     func.__name__ = '__r{}__'.format(name)
   37     return func
   38 
   39 
   40 def _inplace_binary_method(ufunc, name):
   41     """Implement an in-place binary method with a ufunc, e.g., __iadd__."""
   42     def func(self, other):
   43         return ufunc(self, other, out=(self,))
   44     func.__name__ = '__i{}__'.format(name)
   45     return func
   46 
   47 
   48 def _numeric_methods(ufunc, name):
   49     """Implement forward, reflected and inplace binary methods with a ufunc."""
   50     return (_binary_method(ufunc, name),
   51             _reflected_binary_method(ufunc, name),
   52             _inplace_binary_method(ufunc, name))
   53 
   54 
   55 def _unary_method(ufunc, name):
   56     """Implement a unary special method with a ufunc."""
   57     def func(self):
   58         return ufunc(self)
   59     func.__name__ = '__{}__'.format(name)
   60     return func
   61 
   62 
   63 class NDArrayOperatorsMixin(object):
   64     """Mixin defining all operator special methods using __array_ufunc__.
   65 
   66     This class implements the special methods for almost all of Python's
   67     builtin operators defined in the `operator` module, including comparisons
   68     (``==``, ``>``, etc.) and arithmetic (``+``, ``*``, ``-``, etc.), by
   69     deferring to the ``__array_ufunc__`` method, which subclasses must
   70     implement.
   71 
   72     It is useful for writing classes that do not inherit from `numpy.ndarray`,
   73     but that should support arithmetic and numpy universal functions like
   74     arrays as described in `A Mechanism for Overriding Ufuncs
   75     <../../neps/nep-0013-ufunc-overrides.html>`_.
   76 
   77     As an trivial example, consider this implementation of an ``ArrayLike``
   78     class that simply wraps a NumPy array and ensures that the result of any
   79     arithmetic operation is also an ``ArrayLike`` object::
   80 
   81         class ArrayLike(np.lib.mixins.NDArrayOperatorsMixin):
   82             def __init__(self, value):
   83                 self.value = np.asarray(value)
   84 
   85             # One might also consider adding the built-in list type to this
   86             # list, to support operations like np.add(array_like, list)
   87             _HANDLED_TYPES = (np.ndarray, numbers.Number)
   88 
   89             def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
   90                 out = kwargs.get('out', ())
   91                 for x in inputs + out:
   92                     # Only support operations with instances of _HANDLED_TYPES.
   93                     # Use ArrayLike instead of type(self) for isinstance to
   94                     # allow subclasses that don't override __array_ufunc__ to
   95                     # handle ArrayLike objects.
   96                     if not isinstance(x, self._HANDLED_TYPES + (ArrayLike,)):
   97                         return NotImplemented
   98 
   99                 # Defer to the implementation of the ufunc on unwrapped values.
  100                 inputs = tuple(x.value if isinstance(x, ArrayLike) else x
  101                                for x in inputs)
  102                 if out:
  103                     kwargs['out'] = tuple(
  104                         x.value if isinstance(x, ArrayLike) else x
  105                         for x in out)
  106                 result = getattr(ufunc, method)(*inputs, **kwargs)
  107 
  108                 if type(result) is tuple:
  109                     # multiple return values
  110                     return tuple(type(self)(x) for x in result)
  111                 elif method == 'at':
  112                     # no return value
  113                     return None
  114                 else:
  115                     # one return value
  116                     return type(self)(result)
  117 
  118             def __repr__(self):
  119                 return '%s(%r)' % (type(self).__name__, self.value)
  120 
  121     In interactions between ``ArrayLike`` objects and numbers or numpy arrays,
  122     the result is always another ``ArrayLike``:
  123 
  124         >>> x = ArrayLike([1, 2, 3])
  125         >>> x - 1
  126         ArrayLike(array([0, 1, 2]))
  127         >>> 1 - x
  128         ArrayLike(array([ 0, -1, -2]))
  129         >>> np.arange(3) - x
  130         ArrayLike(array([-1, -1, -1]))
  131         >>> x - np.arange(3)
  132         ArrayLike(array([1, 1, 1]))
  133 
  134     Note that unlike ``numpy.ndarray``, ``ArrayLike`` does not allow operations
  135     with arbitrary, unrecognized types. This ensures that interactions with
  136     ArrayLike preserve a well-defined casting hierarchy.
  137 
  138     .. versionadded:: 1.13
  139     """
  140     # Like np.ndarray, this mixin class implements "Option 1" from the ufunc
  141     # overrides NEP.
  142 
  143     # comparisons don't have reflected and in-place versions
  144     __lt__ = _binary_method(um.less, 'lt')
  145     __le__ = _binary_method(um.less_equal, 'le')
  146     __eq__ = _binary_method(um.equal, 'eq')
  147     __ne__ = _binary_method(um.not_equal, 'ne')
  148     __gt__ = _binary_method(um.greater, 'gt')
  149     __ge__ = _binary_method(um.greater_equal, 'ge')
  150 
  151     # numeric methods
  152     __add__, __radd__, __iadd__ = _numeric_methods(um.add, 'add')
  153     __sub__, __rsub__, __isub__ = _numeric_methods(um.subtract, 'sub')
  154     __mul__, __rmul__, __imul__ = _numeric_methods(um.multiply, 'mul')
  155     __matmul__, __rmatmul__, __imatmul__ = _numeric_methods(
  156         um.matmul, 'matmul')
  157     if sys.version_info.major < 3:
  158         # Python 3 uses only __truediv__ and __floordiv__
  159         __div__, __rdiv__, __idiv__ = _numeric_methods(um.divide, 'div')
  160     __truediv__, __rtruediv__, __itruediv__ = _numeric_methods(
  161         um.true_divide, 'truediv')
  162     __floordiv__, __rfloordiv__, __ifloordiv__ = _numeric_methods(
  163         um.floor_divide, 'floordiv')
  164     __mod__, __rmod__, __imod__ = _numeric_methods(um.remainder, 'mod')
  165     __divmod__ = _binary_method(um.divmod, 'divmod')
  166     __rdivmod__ = _reflected_binary_method(um.divmod, 'divmod')
  167     # __idivmod__ does not exist
  168     # TODO: handle the optional third argument for __pow__?
  169     __pow__, __rpow__, __ipow__ = _numeric_methods(um.power, 'pow')
  170     __lshift__, __rlshift__, __ilshift__ = _numeric_methods(
  171         um.left_shift, 'lshift')
  172     __rshift__, __rrshift__, __irshift__ = _numeric_methods(
  173         um.right_shift, 'rshift')
  174     __and__, __rand__, __iand__ = _numeric_methods(um.bitwise_and, 'and')
  175     __xor__, __rxor__, __ixor__ = _numeric_methods(um.bitwise_xor, 'xor')
  176     __or__, __ror__, __ior__ = _numeric_methods(um.bitwise_or, 'or')
  177 
  178     # unary methods
  179     __neg__ = _unary_method(um.negative, 'neg')
  180     __pos__ = _unary_method(um.positive, 'pos')
  181     __abs__ = _unary_method(um.absolute, 'abs')
  182     __invert__ = _unary_method(um.invert, 'invert')