In the numpy documentation of subclassing ndarray here. It is said that
ndarray.__new__, passes__array_finalize__the new object, of our own class (self) as well as the object from which the view has been taken (obj).
I understand ndarray.__new__ can create the new object self and pass that to __array_finalize__, but how does it get the obj from where it is called? From the signature of ndarray.__new__, looks like obj does not get passed from the calling function. So does ndarray.__new__ use some deep magic (probably at the C level) to determine where it is called (i.e. constructor call, view casting or new from template)?
TL:DR: it's the
bufferargument tonp.ndarray.__new__(...). The numpy docs on subclassing discuss creating a new object, a view, and a new-from-template. They show you how to create a new object of your subclass from scratchMySubClass(...)and a view object of your subclassarr.view(MySubClass), but they don't show you how to create a new-from-template of your subclass, other than mentioning that it happens in slicing.You can see this by:
gives
array([2.]). Obviously, the object template is passed as a buffer, so things like striding, order, shape, dtype affect how the data inarris interpreted.As @tim-roberts pointed out, the
InfoArrayexample is helpful, and in fact contains the complete call signature. I couldn't find it myself, possibly as numpy._core.__init__.pyi is deliberately left empty. Nevertheless, the type checker did find the full signature:My use case, since Tim asked: My subclass carries around properties that refer to axes definitions (e.g.
arr.ax_time) in order to make some math clearer (e.g.differentiate(arr, axis=arr.ax_time)). That meant thatndarray.view(MyClass)doesn't make a whole lot of sense, so I wanted to modify the example test (test_ufunc_override_with_super) that used standard views to use new-from-template instead. I know I can test this via slicing (I modify__getitem__), but I wasn't sure if that was the only way new-from-template is used.