NumPy配列ndarrayをイミュータブル(書き換え禁止)に設定

Posted: | Tags: Python, NumPy

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を作成した場合、WRITEABLETrueに設定されており、値を更新することが可能。

a[0] = 100

print(a)
# [100   1   2]

WRITEABLEFalseとすると書き換え禁止となり、値を更新しようとするとエラーとなる。

a.flags.writeable = False

# a[0] = 0
# ValueError: assignment destination is read-only

.writeable['WRITEABLE']で変更するほか、setflags()というメソッドでも設定値を変更できる。setflags()では引数writeWRITEABLEに対応している。

a.flags['WRITEABLE'] = False
a.setflags(write=False)

WRITEABLE属性を変更できない場合もあり

WRITEABLE属性は常に変更できるわけではない。

例えば、スライスなどでnumpy.ndarray配列のビューを生成した場合、元の配列が書き換え禁止(WRITEABLEFalse)だとビューも書き換え禁止となる。

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]

ビューとコピーの判定などについては以下の記事を参照。

関連カテゴリー

関連記事