Immutable numpy array?
Asked Answered
A

3

101

Is there a simple way to create an immutable NumPy array?

If one has to derive a class from ndarray to do this, what's the minimum set of methods that one has to override to achieve immutability?

Adjective answered 4/4, 2011 at 16:18 Comment(2)
Why do you need immutability?Ruel
@KennyTM To avoid coding errors caused by accidentally modifying something that's assumed invariant.Adjective
B
149

You can make a numpy array unwriteable:

a = np.arange(10)
a.flags.writeable = False
a[0] = 1
# Gives: ValueError: assignment destination is read-only

Also see the discussion in this thread:

http://mail.scipy.org/pipermail/numpy-discussion/2008-December/039274.html

and the documentation:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flags.html

Bichromate answered 4/4, 2011 at 16:29 Comment(13)
Alternatively, a.setflags(write=False).Handbag
@lafrasu Which would you say is the preferred form, setflags() or flags.writeable=?Adjective
@aix: A quick look at the documentation would make it seem as if the two approaches are identical. Personally, I prefer using a method to set attributes.Handbag
Does this also make it memoizable?Maurer
IMPORTANT!! Numpy DOES NOT have an immutable array. Arrays with .flags.writeable = False are still not immutable. If x is an array, y = x[:]; x.flags.writeable = False; y[0] = 5 updates the first element of x to 5.Homocercal
@JamesParker you do get an error if you set the writeable flag before creating y.Ruthannruthanne
@JamesParker It seems the flags come with the array when you slice. So if the writable flag is set to False before you slice then then y above would fail on update.Alberich
@DamonMaria I tested it and that seems to be correct. You can only change y.flags.writeable = True when that value for x is true. It's just changing writeable for x does not update that of y directly.Homocercal
@James Parker apparently the order is important. A slice before setting writable to False, is not blocked. “...locking a base object does not lock any views that already reference it”. See under writable tag numpy.org/doc/stable/reference/generated/…Syringe
FYI, I used arr.flags.writeable = False, but then I called for i in range(5): np.random.shuffle(arr[:,i]), which shuffled the array in place - no errors or warnings.Ladin
@Ladin strange, I just tried it and I get an error...Kanazawa
@Vinzent, sorry, my comment was missing an important detail - I used arr = np.arange(30).reshape(6,5). If you tried for i in range(5): np.random.shuffle(arr[:,i]) on arr = np.arange(10) you would definitely get an IndexError.Ladin
It seems that cv2 ignores this flag. I put it on an image so I force myself to remember doing frame.copy() before drawing on it, but cv2.line(frame, ...) doesn't throw an error. ``` a = np.zeros((FRAME_HEIGHT, FRAME_WIDTH, 3), dtype=np.uint8) a.setflags(write=False) cv2.line(a, (100, 100), (200, 200), (255, 255, 255), 10) cv2_imshow(a) ```Peoples
L
1

Setting the flag directly didn't work for me, but using ndarray.setflags did work:

a = np.arange(10)
a.setflags(write=False)
a[0] = 1  # ValueError
Liddell answered 31/1, 2022 at 21:30 Comment(0)
E
0

I have a subclass of Array at this gist: https://gist.github.com/sfaleron/9791418d7023a9985bb803170c5d93d8

It makes a copy of its argument and marks that as read-only, so you should only be able to shoot yourself in the foot if you are very deliberate about it. My immediate need was for it to be hashable, so I could use them in sets, so that works too. It isn't a lot of code, but about 70% of the lines are for testing, so I won't post it directly.

Note that it's not a drop-in replacement; it won't accept any keyword args like a normal Array constructor. Instances will behave like Arrays, though.

Ezekiel answered 2/9, 2021 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.