Python

【Python】ミュータブルとイミュータブル

この記事では、Pythonのミュータブル(mutable)とイミュータブル(immutable)なオブジェクトについて解説します。

ミュータブルとは、値を変更できるオブジェクトのこと で、イミュータブルとは、値が変更できないオブジェクトのこと を言います。

それでは、もう少し詳しくミュータブルとイミュータブルについて見てきましょう!

ミュータブルとイミュータブルとは?

値を変更できるオブジェクトのことを「ミュータブル」と呼び、値が変更できないオブジェクトのことを「イミュータブル」と呼びます。

値が変更できるかどうかと言いましたが、ここで重要なのは「同じオブジェクトのまま値が変更できるかどうか」ということです。

例えば、int型はイミュータブルですが、以下のコードを見てください。

num = 1

num = 2

値を変更しているかに見えますが単に異なるオブジェクトを代入しているに過ぎません。

同じオブジェクトのまま値を変更するには関数やプロパティを使えばいいですが、int型はイミュータブルなのでそのような関数は実装されていません。

なので、プロパティから直接書き換えてみましょう!

num = 1

# すべてAttributeError
num.real = 2
num.imag = 2
num.numerator = 2
num.denominator = 2

すべてAttributeErrorが発生しました❗️

このように、同じオブジェクトのまま値が変更できないオブジェクトをイミュータブルと呼び、反対に変更できるオブジェクトをミュータブルと呼びます。

リストなんかは以下のように同じオブジェクトのまま値だけ変更することができます。

l = [1, 2]
l.append(3)

print(l)
# [1, 2, 3]

同じオブジェクトかどうかは、識別値(ID)で確認できます。

オブジェクトの識別値(ID)について

ミュータブルとイミュータブルな型一覧

ミュータブルの型には、以下のようなものがあります。

  • list
  • dict
  • set
  • bytearray
  • ユーザー定義クラス

イミュータブルの型には、以下のようなものがあります。

  • bool
  • int
  • flaot
  • complex
  • str
  • tuple
  • range
  • bytes
  • file object

例外的なイミュータブル

イミュータブルな型は、同じオブジェクトのまま値を変更できないと言ってきましたが例外的なものもあります。

それは「ミュータブルな要素を持つイミュータブル」です。

例えば、タプルの中にリストが格納されている場合などです。

t = (1, 2, [])
identity = id(t)  # 変更前のID

t[2].append(99)
print(t)
# (1, 2, [99])

# 変更後のIDと比較
print(identity == id(t))
# True

このように、ミュータブルな要素を持つイミュータブルは、IDを変更せずとも値を書き換えることができます。

ミュータブルなオブジェクトの注意点

ミュータブルなオブジェクトは、他の変数に代入して使用される場合、元のオブジェクトにも影響を与えてしまいます。

l = []

# l を new_l に代入
new_l = l
# new_l に要素を追加
new_l.append(1)

# l に要素が追加されている
print(l)  # [1]

関数の引数に渡す際も同様です。

l = []

def func(data: list):
    data.append(1)

func(l)
print(l)  # [1]

元のオブジェクトに影響を与えたくない場合はコピーを生成します。

オブジェクトをコピーする方法

まとめ

この記事では、ミュータブルとイミュータブルについて解説しました。

ミュータブルなオブジェクトを使用する場合には、元のオブジェクトに影響があるのかどうかを注意して使用しましょう。

それでは今回の内容はここまでです。ではまたどこかで〜( ・∀・)ノ