NumPy配列ndarrayをイミュータブル(書き換え禁止)に設定
NumPy配列numpy.ndarray
は基本的にミュータブルで要素を指定して値を更新可能。numpy.ndarray
の設定を変更することでイミュータブル(書き換え禁止, read-only)にできる。
誤って値を更新してしまうのを防ぐのに便利。
ここでは以下の内容について説明する。
ndarray
のメモリレイアウト情報を格納しているflags
WRITEABLE
属性で配列をイミュータブル(書き換え禁止)に設定WRITEABLE
属性を変更できない場合もあり
最後に説明するように、元の配列が書き換え可能である場合は、そのビューを書き換え禁止にしても元の配列から要素の値が更新できるので注意。
ndarrayのメモリレイアウト情報を格納しているflags
numpy.ndarray
のメモリレイアウトの情報はflags
に格納されている。
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'>
numpy.flagsobj
という独自の型だが、.属性名
や['属性名']
として各属性の値を確認できる。.属性名
は小文字で['属性名']
は大文字なので注意。
print(a.flags.writeable)
# True
print(a.flags['WRITEABLE'])
# True
WRITEABLE属性で配列をイミュータブル(書き換え禁止)に設定
numpy.ndarray
が書き換え禁止かどうかの設定はWRITEABLE
属性。
上の例のように新たにnumpy.ndarray
を作成した場合、WRITEABLE
はTrue
に設定されており、値を更新することが可能。
a[0] = 100
print(a)
# [100 1 2]
WRITEABLE
をFalse
とすると書き換え禁止となり、値を更新しようとするとエラーとなる。
a.flags.writeable = False
# a[0] = 0
# ValueError: assignment destination is read-only
.writeable
や['WRITEABLE']
で変更するほか、setflags()
というメソッドでも設定値を変更できる。setflags()
では引数write
がWRITEABLE
に対応している。
a.flags['WRITEABLE'] = False
a.setflags(write=False)
WRITEABLE属性を変更できない場合もあり
WRITEABLE
属性は常に変更できるわけではない。
例えば、スライスなどでnumpy.ndarray
配列のビューを生成した場合、元の配列が書き換え禁止(WRITEABLE
がFalse
)だとビューも書き換え禁止となる。
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
元の配列が書き換え禁止の場合、ビューのWRITEABLE
属性をTrue
に変更して書き換え禁止を解除することはできない。
# a_view.flags.writeable = True
# ValueError: cannot set WRITEABLE flag to True of this array
元の配列のWRITEABLE
属性をTrue
にしてもビューのWRITEABLE
属性はFalse
のまま変わらないが、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]
ビューのWRITEABLE
属性がFalse
であっても、元の配列のWRITEABLE
属性がTrue
であれば元の配列からは更新可能。注意。
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]
コピーの場合は新たな配列が生成されるので元の配列とは独立してWRITEABLE
属性を設定可能。
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]
ビューとコピーの判定などについては以下の記事を参照。