How to find the `base` of a record array

70 Views Asked by At

How is base determined for record arrays? The docs seem to describe the same behavior as regular arrays, but that's not what it is. Here's a simple array, and a record array created from it.

>>> arr = np.zeros(10, dtype=[('a', float), ('b', int), ('c', int)])
>>> rec = arr.view(np.recarray)

The base of the record array is correctly set

>>> arr is rec
False

>>> arr is rec.base
True

The base is correctly set for field accesses of the regular array.

>>> arr['a'].base is arr
True

However, for the record array I can't determine what the base is. It's not the regular array, the record array, None, or anything else that I've tried.

>>> rec['a'].base is arr
False

>>> rec['a'].base is rec
False

>>> rec['a'].base is None
False

>>> rec['a'].base is rec['a']
False

>>> rec['a'].base is rec['a'].base
False

>>> f = rec['a']
>>> f.base is f
False

It behaves as expected for indexing slices

>>> arr[:3].base is arr
True

>>> rec[:3].base is rec
True

And it definitely still points to the same memory

>>> arr[0]
(0., 0, 0)

>>> rec['a'] = 1

>>> arr[0]
(1., 0, 0)

So, how can the actual base of a record array be found?

1

There are 1 best solutions below

0
user2357112 On BEST ANSWER

The "actual base" is still the base attribute. If you want to follow the base chain recursively, go ahead:

def recursive_base(arr):
    while arr.base is not None:
        arr = arr.base
    return arr

If you want to see why rec['a'].base is not rec, then take a look at recarray.__getitem__:

def __getitem__(self, indx):
    obj = super(recarray, self).__getitem__(indx)

    # copy behavior of getattr, except that here
    # we might also be returning a single element
    if isinstance(obj, ndarray):
        if obj.dtype.fields:
            obj = obj.view(type(self))
            if issubclass(obj.dtype.type, nt.void):
                return obj.view(dtype=(self.dtype.type, obj.dtype))
            return obj
        else:
            return obj.view(type=ndarray)
    else:
        # return a single element
        return obj

In your case, the returned object is a view of the result returned by ndarray.__getitem__, and the base is the object returned by ndarray.__getitem__. Generally, though, it's not guaranteed whether NumPy will flatten the base chain when setting a new array's base.