Search code examples
pythonalgorithmnumpyattributesattr

Is it a good way to use numpy.ndarray.strides attribute like this?


While browsing through attributes, I found that I can change np.ndarray.strides attribute explicitly like so:

arr = np.array([8, 3, 4], dtype=np.uint16)
arr.strides = 1
arr
>>> array([  8, 768,   3], dtype=uint16)

I know intuitively this is not safe way to assign an attribute explicitly (might be antipattern). Despite that, I know very well, what it is supposed to do.

Another way to get my expected result is:

np.lib.stride_tricks.as_strided(arr, shape=(3,), strides=(1,))

I'm looking for any guidelines about patterns of programming that helps to understand, should I avoid setting attributes like this.

Also, is there a safer way in numpy to assign a new value to .strides attribute?


Solution

  • np.lib.stride_tricks.sliding_window_view is a newer, safer cover for as_strided. However most uses of these use a strides that is as big as the original (here 2). They return a view, rather than modify the array itself.

    Your array, and 2 ways of viewing the individual bytes:

    In [529]: arr = np.array([8,3,4],'uint16')
    In [530]: arr
    Out[530]: array([8, 3, 4], dtype=uint16)
    In [531]: arr.tobytes()
    Out[531]: b'\x08\x00\x03\x00\x04\x00'
    In [532]: arr.view('uint8')
    Out[532]: array([8, 0, 3, 0, 4, 0], dtype=uint8)
    

    your strides change is just a portion of

    In [533]: np.lib.stride_tricks.as_strided(arr, strides=(1,), shape=(6,))
    Out[533]: array([   8,  768,    3, 1024,    4,    0], dtype=uint16)
    
    In [535]: _.astype('uint8')
    Out[535]: array([8, 0, 3, 0, 4, 0], dtype=uint8)
    

    I think the 768 comes from the 0 3

    In [537]: np.array([0,3],'uint8').view('uint16')
    Out[537]: array([768], dtype=uint16)
    

    So even though your strides is (1,), it is still uint16 as the dtype, so displaying (8,0), (0,3), (3,0), [(0,4), (4,0)]. Actually the safe as_strided should have used shape=(5,), since the 6 actually "steps off the end".

    So while changing strides as you do is possible, I don't think it's useful. I haven't see anyone else use it. And as I show, interpreting the results requires some in depth knowledge of dtypes (and their relation to shape and strides).