Subclassed Ndarray is relatively simple, but it is a bit more complex than other Python objects.

Ndarrays and objects are created

Subclassing ndarray is complicated because new instances of the Ndarray class can be generated in three different ways.

1. The constructor call shown is in MySubClass (params), which is the common way to create Pythton instances.

2. View conversion, which converts existing NdarRay to the given subclass

3. New template functionality to create new instances from template instances, including returning slices from subclassed arrays, creating return types from ufunc, and copying arrays.

The last two are nDARRay features – to support things like array slicing. The complexity of subclassing Ndarray is due to the fact that NumPy must support the latter two mechanisms for creating instance paths.

View transformation

View cast is the standard Ndarray mechanism by which we can take the NDARray of any subclass and return the view of the array as another (specified) subclass.

Create a new one from the template

When NumPy discovers that it needs to create a new instance from a template instance, a new instance of an Ndarray subclass can also be implemented using a very similar mechanism to looking at type conversions, most notably when getting a slice of the subclass array.

A slice is a view of the original C_arr data, so when we get a view from nDARray, we return a new Ndarray that belongs to the same class and points to the original data.

We use views like this in other places where we use Ndarray, such as copying arrays (c_arr.copy()), creating ufunc output arrays, and reducing methods (c_arr.mean()).

Add attributes to an existing array

Using an existing standard NDARray class, cast it to our type and add an extra attribute.

So:

Subclassing and downstream compatibility

When subclassing Ndarray or creating duck types that mimic the Ndarray interface, you should decide how the API will align with NumPy’s API. For convenience, many NumPy functions with corresponding NDARray methods (e.g., sum, mean, take, recapay) work by checking if the function’s first argument has a method with the same name. The method is called if it exists, rather than casting the argument to a NumPy array.

For example, if you want your subclass or duck_type to be compatible with NumPy’s sum function, then the method signature of the object’s sum method should look like this:

This is the exact same method signature as Np. sum, so if we now call Np. sum on this object, NumPy will call the object’s own sum method and pass the arguments enumerated above into the signature without raising an error because the signatures are fully compatible with each other.

However, if you decide to deviate from this signature and do the following:

The object is no longer compatible with Np. sum, because if np.sum is called, it passes in the unexpected arguments out and keepdims, raising TypeError.

If you want to learn Python, but can’t find a path or resources to learn it, welcome to programming at your fingertips.