🐥

【Python】ミュータブルとイミュータブルの違い

2024/11/07に公開

Pythonを学習している際に、ミュータブルとイミュータブルの違いを学んだのでまとめます。

オブジェクトとは

前提知識であるオブジェクトについてです。
Pythonでは、x=1、y=[100, 200]のようにxとyに値を代入すると、Xとyはそれぞれ以下の図ように、メモリ上のオブジェクトを参照するようになります。
このオブジェクトは一意の識別子であるid、値、型などの情報を持ち、idはオブジェクトがメモリ上のどこにあるのかを示しています。
この例では、xはid=4449472576のオブジェクトを参照しており、yはid=4455662752のオブジェクトを参照している状態です。
(例)

x = [100, 200]
print(f'xのidは {id(x)}') # yのidは 4449472576
print(f'xの型は {type(x)}') # yの型は <class 'list'>

y = 1
print(f'yのidは {id(x)}') # yのidは 4455662752
print(f'yの型は {type(x)}') # yの型は <class 'int'>

ミュータブルとイミュータブルな値の違い

ここで本題です。
ミュータブルは「オブジェクトの値を変更できる」、イミュータブルは「オブジェクトの値を変更できない」ことを意味しています。
これについて具体例を使って詳しく見ていきます。

ミュータブルの例

ミュータブルなオブジェクトは、リスト、辞書、集合があります。

x = [100, 200]
print(x) # [100, 200]
print(f'xのidは {id(x)}') # xのidは 4449472576
x[0] = 300
print(x) # [300, 200]
print(f'xのidは {id(x)}') # xのidは 4449472576(同じid)

xの変更前後でidが同じままであるため、xの参照先が同じであることを意味しています。

イミュータブルの例

イミュータブルなオブジェクトは、整数、浮動小数点数、文字列、タプルがあります。
整数で試してみます。

y = 1
print(y) # 1
print(f'yのidは {id(y)}') # yのidは 4455662752
y = 3
print(y) # 3
print(f'yのidは {id(y)}') # yのidは 4458931424(異なるid)

yの変更前後でidが異なることが分かります。
これは、整数がイミュータブルな値なので、オブジェクトの値を直接変更することができずに、新しくid=4458931424のオブジェクトが生成され、yの参照先が新しいオブジェクトに変更されたことを示します。

イミュータブルの要素にミュータブルの要素が含まれる場合

タプルの中にリストが含まれる場合を見ていきます。

z = ('hoge', [1, 2, 3])
print(f'z[0]のidは {id(z[0])}') # 4390627216
print(z[1][1]) # 2
print(f'z[1]のidは {id(z[1])}') # 4503982144
print(f'z[1][1]のidは {id(z[1][1])}') # 4514923712(変更前)

# z[0] = 4 # エラー
# z[1] = [4, 5, 6] # エラー

z[1][1] = 20 #(リストの要素を変更)
print(z[1]) # [1, 20, 3]
print(f'z[1]のidは {id(z[1])}') # 4503982144(※idが変更されている)
print(f'z[1][1]のidは {id(z[1][1])}') # 4514924288

タプルはイミュータブルかつ、要素の参照先の変更が認められていないので、z[0]とz[1]を変更しようとするとエラーとなります。
しかしリストはミュータブルなので、リストの各要素であれば変更できます。
上の例ではz[1][1]を20に変更しています。
z[1][1]自体は整数でイミュータブルなので、z[1][1]変更前後のidも変更されています。

まとめ

上の例のとおり、
ミュータブル:オブジェクトの値を直接変更することができ、参照先は変わらない
イミュータブル:オブジェクトの値を直接変更できず、値を変更しようとすると新しいオブジェクトが作成され、参照先オブジェクトが変更される
タプルにリストが含まれる場合:タプルの各要素を変更できないが、タプル内のリストの要素を変更できる

ことが分かりました。
ミュータブルとイミュータブルな値の違いをまとめると以下になります。

ミュータブル イミュータブル
特徴 値を直接変更できる 値を直接変更できず、参照先を変更する
リスト、辞書、集合 ... 整数、浮動小数点数、文字列、タプル ...
idの変化 同じidを保持する 変更すると新しいidが生成される
メモリ効率 同じオブジェクトを保持するため効率的 変更時に新しいオブジェクトを生成するため、状況によってはメモリ消費が増える

参考

以下の記事を参考にさせていただきました。
https://qiita.com/kojikawamura/items/50a7d1d426c12a8c702b

Discussion