[Numpy-discussion] __skip_array_function__ discussion summary

Stefan van der Walt stefanv at berkeley.edu
Thu May 23 19:20:36 EDT 2019


On Thu, 23 May 2019 14:33:17 -0700, Sebastian Berg wrote:
> Those two options further have very different goals in mind for the
> final usage of the protocol. So that right now the solution is to step
> back, not include the addition and rather gain experience with the
> NumPy 1.17 release that includes `__array_function__` but not
> `__skip_array_function`.

To emphasize how this solves the API exposure problem:

If `__skip_array_function__` is being made available, the user can
implement `ones_like` for their custom class as:

class MyArray:
    def __array_function__(func, types, *args, **kwargs):
        if func == np.ones_like:
            return np.ones_like.__skip_array_function__(x)

Without it, they are forced to reimplement `ones_like` from scratch.
This ensures that they never rely on any internal behavior of
`np.ones_like`, which may change at any time to break for their custom
array class.

Here's a concrete example:

The user wants to override `ones_like` and `zeros_like` for their custom
array.  They implement it as follows:

class MyArray:
    def __array_function__(func, types, *args, **kwargs):
        if func == np.ones_like:
            return np.ones_like.__skip_array_function__(*args, **kwargs)
        elif func == np.zeros_like:
            return MyArray(...)

Would this work?  Well, it depends on how NumPy implements `ones_like`
internally.  If NumPy used `__skip_array_function__ consistently
throughout, it would not work:

def np.ones_like(x):
    y = np.zeros_like.__skip_array_function__(x)
    y.fill(1)
    return y

If, instead, the implementation was

def np.ones_like(x):
    y = np.zeros_like(x)
    y.fill(1)
    return y

it would work.  *BUT*, it would be brittle, because our internal
implementation may easily change to:

def np.ones_like(x):
    y = np.empty_like(x)
    y.fill(1)
    return y

And if `empty_like` isn't implemented by MyArray, this would break.


The workaround that Stephan Hoyer mentioned (and that will have to be
used in 1.17) is that you can still use the NumPy machinery to operate
on pure arrays:

class MyArray:
    def __array_function__(func, types, *args, **kwargs):
        if func == np.ones_like:
            x_arr = np.asarray(x)
            ones = np.ones_like(x_arr)
            return MyArray.from_array(ones)

Stéfan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 529 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/numpy-discussion/attachments/20190523/14e171ed/attachment.sig>


More information about the NumPy-Discussion mailing list