<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>In most cases, I suspect that the overhead of a function call and checking several arguments for "__array_function__" will be negligible, like the situation for __array_ufunc__. I'm not strongly opposed to either of your proposed solutions, but I do think it would be a little strange to insist that we need a solution for __array_function__ when __array_ufunc__ was fine.</div></div></div></blockquote><div><br></div><div>Ufuncs actually do try to speed-up array checks - but indeed the same can (and should) be done for `__array_ufunc__`. They also do have `subok`. This currently ignored but that is mostly because looking for it in `kwargs` is so damn slow!<br><br></div><div>Anyway, my main point was that it should be explicitly mentioned as a constraint that for pure ndarray input, things should be really fast.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>A. Two
"namespaces", one for the undecorated base functions, and one completely trivial one for the
decorated ones. The idea would be that if one knows one is dealing with
arrays only, one would do `import numpy.array_only as np` (i.e., the reverse of the suggestion currently in the NEP, where the decorated ones are in their own namespace - I agree with the reasons for discounting that one).<br></div></div></div></blockquote><div><br></div><div>I will mention this as a possibility.</div><div><br></div><div>I do think there is something to be said for clear separation of overloaded and non-overloaded APIs. But f I were to choose between adding numpy.api and numpy.array_only, I would pick numpy.api, because of the virtue of preserving the existing numpy namespace as it currently exists.</div></div></div></blockquote><div><br></div><div>Good point. Overall, the separate namespaces probably is not the way to do.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><span style="color:rgb(33,33,33);font-size:13px">B. Automatic insertion by the decorator of an `array_only=np._NoValue` (or `coerce` and perhaps `subok=...` if not present) in the function signature, so that users who know that they have arrays only could pass `array_only=True` (name to be decided).</span></div></div></blockquote><div><br></div><div>Rather than adding another argument to every NumPy function, I would rather encourage writing np.asarray() explicitly.</div></div></div></blockquote><div><br></div><div>Good point - just as good as long as the check for all-array is very fast (which it should be - `arg.__class__ is np.ndarray` is fast!).<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div>Note that both A and B could also address, at least partially, the problem of sometimes wanting to just use the old coercion methods, i.e., not having to implement every possible numpy function in one go in a new `__array_function__` on one's class.</div></div></blockquote><div><br></div><div>Yes, agreed. </div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div></div><div>1. I'm rather unclear about the use of `types`. It can help me decide what to do, but I would still have to find the argument in question (e.g., for Quantity, the unit of the relevant argument). I'd recommend passing instead a tuple of all arguments that were inspected, in the inspection order; after all, it is just a `arg.__class__` away from the type, and in your example you'd only have to replace `issubclass` by `isinstance`.<br></div></div></blockquote><div><br></div><div>The virtue of a `types` argument is that we can deduplicate arguments once, rather than in each __array_function__ check. This could result in significantly more efficient code, e.g,. when np.concatenate() is called on 10,000 arrays with only two unique types, we don't need to loop through all 10,000 again objects to check that overloading is valid.<br></div></div></div></blockquote><div><br></div><div>I think one might still want to know *where* the type occurs (e.g., as an output or index would have different implications). Possibly, a solution would rely on the same structure as used for the "dance". But as a general point, I don't see the advantage of passing types rather than arguments - less information for no benefit.<br> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div></div><div>Even for Quantity, I suspect you will want two layers of checks:</div><div>1. A check to verify that every argument is a Quantity (or something coercible to a Quantity). This could use `types` and return `NotImplemented` when it fails.</div><div>2. A check to verify that units match. This will have custom logic for different operations and will require checking all arguments -- not just their unique types.</div></div></div></blockquote><div><br></div><div>Not sure. With, Quantity I generally do not worry about other types, but rather look at units attributes, assume anything without is dimensionless, cast Quantity to array with the right unit, and then defer to `ndarray`.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_quote"><div>For many Quantity functions, the second check will indeed probably be super simple (i.e., verifying that all units match). But the first check (with `types`) really is something that basically very overload should do.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div></div><div>2. For subclasses, it would be very handy to have `ndarray.__array_function__`, so one can call super after changing arguments. (For `__array_ufunc__`, there was lots of question about whether this was useful, but it really is!!). [I think you already agreed with this, but want to have it in-place, as for subclasses of ndarray this is just as useful as it would be for subclasses of dask arrays.)<br></div></div></blockquote><div><br></div><div>Yes, indeed.</div></div></div>
<br>______________________________<wbr>_________________<br>
NumPy-Discussion mailing list<br>
<a href="mailto:NumPy-Discussion@python.org">NumPy-Discussion@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/numpy-discussion" rel="noreferrer" target="_blank">https://mail.python.org/<wbr>mailman/listinfo/numpy-<wbr>discussion</a><br>
<br></blockquote></div><br></div></div>