What does (numpy) __array_wrap__ do?

2024/10/12 4:26:11

I am diving into the SciPy LinAlg module for the first time, and I saw this function:

def _makearray(a):new = asarray(a)wrap = getattr(a, "__array_prepare__", new.__array_wrap__)return new, wrap

What does __array_wrap__ do exactly? I found the documentation, but I don't understand this explanation:

 At the end of every ufunc, this method is called on the input object with thehighest array priority, or the output object if one was specified. The ufunc-computed array is passed in and whatever is returned is passed to the user. Subclasses inherit a default implementation of this method, which transforms thearray into a new instance of the object’s class. Subclasses may opt to use thismethod to transform the output array into an instance of the subclass and updatemetadata before returning the array to the user.

Does this just mean it reconverts the output of whatever function back into an array since it was likely broken up into something else for element-by-element processing? Relatedly, regardless of the explanation, what would it mean to get this wrap as an object? What would you do with it?

I am looking at the code for numpy.linalg.inv...what is wrap doing here?

    **a, wrap = _makearray(a)**_assertRankAtLeast2(a)_assertNdSquareness(a)t, result_t = _commonType(a)if a.shape[-1] == 0:# The inner array is 0x0, the ufunc cannot handle this case**return wrap(empty_like(a, dtype=result_t))**signature = 'D->D' if isComplexType(t) else 'd->d'extobj = get_linalg_error_extobj(_raise_linalgerror_singular)ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj)return wrap(ainv.astype(result_t))
Answer

np.ma.masked_array.__array_wrap__ is an example of a array subclass that updates the metadata (the mask).

File:        /usr/lib/python3/dist-packages/numpy/ma/core.py
Definition:  np.ma.masked_array.__array_wrap__(self, obj, context=None)
Source:def __array_wrap__(self, obj, context=None):"""Special hook for ufuncs.Wraps the numpy array and sets the mask according to context."""

np.matrix.__array_wrap__ appears to inherit the ndarray version. My guess it's because matrix, while a subclass, does not have metadata that needs updating.

Generally the idea with a hook, is that it's a function that is called deep within the normal processing. The default method might not do anything. But it's a way that the subclass can take special action. The class developer writes hooks like this so that the class user will not have to worry about those details. With a __...__ name it isn't part of the public interface - though Python lets us peak under the curtain.

An example of wrapping, i.e returning an array with the same class as the inputs is:

In [659]: np.cumsum(np.arange(10))
Out[659]: array([ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45], dtype=int32)In [660]: np.cumsum(np.matrix(np.arange(10)))
Out[660]: matrix([[ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45]], dtype=int32In [665]: np.cumsum(np.ma.masked_array(np.arange(10)))
Out[665]: 
masked_array(data = [ 0  1  3  6 10 15 21 28 36 45],mask = False,fill_value = 999999)

The returned values are all the same, but the array subclass varies, depending on the input class.


cumsum might not be the best example. Masked arrays have their own version of cumsum, one that treats the masked values as 0:

In [679]: m=np.ma.masked_array(np.arange(10),np.arange(10)%2)In [680]: m
Out[680]: 
masked_array(data = [0 -- 2 -- 4 -- 6 -- 8 --],mask = [False  True False  True False  True False  True False  True],fill_value = 999999)In [681]: np.cumsum(m)
Out[681]: 
masked_array(data = [0 -- 2 -- 6 -- 12 -- 20 --],mask = [False  True False  True False  True False  True False  True],fill_value = 999999)

add.accumulate is similar to cumsum, but doesn't have a special masked version:

In [682]: np.add.accumulate(np.arange(10))
Out[682]: array([ 0,  1,  3,  6, 10, 15, 21, 28, 36, 45], dtype=int32)In [683]: np.add.accumulate(m)
Out[683]: 
masked_array(data = [ 0  1  3  6 10 15 21 28 36 45],mask = False,fill_value = 999999)

This last is a masked array, but the mask is the default False, and the masked values were included in the sum.

https://en.xdnf.cn/q/69692.html

Related Q&A

SqlAlchemy TIMESTAMP on update extra

I am using SqlAlchemy on python3.4.3 to manage a MySQL database. I was creating a table with:from datetime import datetimefrom sqlalchemy import Column, text, create_engine from sqlalchemy.types import…

Is it possible to pass a dictionary with extraneous elements to a Django object.create method?

I am aware that when using MyModel.objects.create in Django, it is possible to pass in a dictionary with keys which correspond to the model fields in MyModel. This is explained in another question here…

When should I use varargs in designing a Python API?

Is there a good rule of thumb as to when you should prefer varargs function signatures in your API over passing an iterable to a function? ("varargs" being short for "variadic" or …

PyPDF2 wont extract all text from PDF

Im trying to extract text from a PDF (https://www.sec.gov/litigation/admin/2015/34-76574.pdf) using PyPDF2, and the only result Im getting is the following string:bHere is my code:import PyPDF2 import …

Python 3.4 decode bytes

I am trying to write a file in python, and I cant find a way to decode a byte object before writing the file, basically, I am trying to decode this bytes string:Les \xc3\x83\xc2\xa9vad\xc3\x83\xc2\xa9s…

No module named unusual_prefix_*

I tried to run the Python Operator Example in my Airflow installation. The installation has deployed webserver, scheduler and worker on the same machine and runs with no complaints for all non-PytohnOp…

Python: Variables are still accessible if defined in try or if? [duplicate]

This question already has answers here:Short description of the scoping rules(9 answers)Closed last year.Im a Python beginner and I am from C/C++ background. Im using Python 2.7.I read this article: A …

Networkx Traveling Salesman Problem (TSP)

I would like to know if there is a function in NetworkX to solve the TSP? I can not find it. Am I missing something? I know its an NP hard problem but there should be some approximate solutions right

Comparing dateutil.relativedelta

Im trying to do a > comparison between two relativedeltas: if(relativedelta(current_date, last_activity_date) > relativedelta(minutes=15)):Here is the output from the debugger window in Eclipse:O…

Python. Argparser. Removing not-needed arguments

I am parsing some command-line arguments, and most of them need to be passed to a method, but not all.parser = argparse.ArgumentParser() parser.add_argument("-d", "--dir", help = &q…