【Python】ミュータブルとイミュータブルの違い
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が生成される |
メモリ効率 | 同じオブジェクトを保持するため効率的 | 変更時に新しいオブジェクトを生成するため、状況によってはメモリ消費が増える |
参考
以下の記事を参考にさせていただきました。
Discussion