NumPy: Make arrays immutable (read-only) with the WRITEABLE attribute
The NumPy array (numpy.ndarray) is mutable by default, which means you can update the values of its elements. By changing the settings of numpy.ndarray, you can make it immutable (read-only).
Making an array immutable can be useful for preventing accidental value updates.
This article covers the following topics.
- The
flagsattribute stores memory layout information ofndarray - Make the
ndarrayimmutable (read-only) with theWRITEABLEattribute - Situations where the
WRITEABLEattribute cannot be changed
Keep in mind that if the original array is writable, you can still update the element values from the original array even if you make its view read-only, as discussed later.
The flags attribute stores memory layout information of ndarray
The memory layout information of numpy.ndarray is stored in the flags attribute.
import numpy as np
a = np.arange(3)
print(a)
# [0 1 2]
print(a.flags)
# C_CONTIGUOUS : True
# F_CONTIGUOUS : True
# OWNDATA : True
# WRITEABLE : True
# ALIGNED : True
# WRITEBACKIFCOPY : False
# UPDATEIFCOPY : False
print(type(a.flags))
# <class 'numpy.flagsobj'>
The flags attribute returns an object of type numpy.flagsobj. You can access its attribute values using either the .attribute_name (lowercase) or ['ATTRIBUTE_NAME'] (uppercase) notation.
print(a.flags.writeable)
# True
print(a.flags['WRITEABLE'])
# True
Make the ndarray immutable (read-only) with the WRITEABLE attribute
You can make the ndarray immutable (read-only) with the WRITEABLE attribute.
When you create a new numpy.ndarray, the WRITEABLE attribute is set to True by default, allowing you to update its values.
a[0] = 100
print(a)
# [100 1 2]
By setting the WRITEABLE attribute to False, the array becomes read-only, and attempting to update its values will result in an error.
a.flags.writeable = False
# a[0] = 0
# ValueError: assignment destination is read-only
You can change the WRITEABLE attribute using either .writeable or ['WRITEABLE'], or you can alternatively change the setting with the setflags() method. In setflags(), the write argument corresponds to the WRITEABLE attribute.
a.flags['WRITEABLE'] = False
a.setflags(write=False)
Situations where the WRITEABLE attribute cannot be changed
The WRITEABLE attribute isn't always changeable.
For example, when you create a view of a numpy.ndarray array with a slice, if the original array is read-only (WRITEABLE is False), the view will also be read-only.
a = np.arange(3)
print(a)
# [0 1 2]
a.flags.writeable = False
a_view = a[1:]
print(a_view)
# [1 2]
print(a_view.flags.writeable)
# False
# a_view[0] = 100
# ValueError: assignment destination is read-only
If the original array is read-only, you cannot change the WRITEABLE attribute of the view to True.
# a_view.flags.writeable = True
# ValueError: cannot set WRITEABLE flag to True of this array
Even if you set the WRITEABLE attribute of the original array to True, the WRITEABLE attribute of the view remains False, but it becomes changeable to True.
a.flags.writeable = True
print(a_view.flags.writeable)
# False
a_view.flags.writeable = True
a_view[0] = 100
print(a_view)
# [100 2]
print(a)
# [ 0 100 2]
If the WRITEABLE attribute of the original array is True, you can update the values from the original array even when the WRITEABLE attribute of the view is False.
a_view.flags.writeable = False
# a_view[1] = 1
# ValueError: assignment destination is read-only
print(a.flags.writeable)
# True
a[1] = 1
print(a)
# [0 1 2]
print(a_view)
# [1 2]
In the case of a copy, a new array is created, so you can set the WRITEABLE attribute independently of the original array.
a.flags.writeable = False
a_copy = a[1:].copy()
print(a_copy)
# [1 2]
print(a_copy.flags.writeable)
# True
a_copy[0] = 100
print(a_copy)
# [100 2]
print(a)
# [0 1 2]
To determine whether an ndarray is a view or a copy and if it shares memory, refer to the following article: