Python イミュータブル・ミュータブル

Pythonにおけるイミュータブル(immutable)とミュータブル(mutable)について説明します。


  • イミュータブル : 値を変えることができないオブジェクト
  • ミュータブル : 値を変えることができるオブジェクト
 データ型イミュータブルミュータブル 
int (整数)   ◯
float (浮動小数点)   ◯
complex (複素数)   ◯
bool (論理)   ◯
str (文字列)   ◯
set (集合)   ◯
dict (辞書)   ◯
list (配列)   ◯
tuple (タプル)   ◯
range   ◯
byte   ◯
bytearray   ◯

イミュータブルなオブジェクトは = (代入式)によって、新たなオブジェクトが生成されます。そのため、変数名が同じでも、代入前と代入後のオブジェクト(id)は異なります。

x = 'Apple'
print(id(x))
>> 139800595449424

x = x + 'Store'
print(id(x))
>> 139800586252080 # idが異なる

ミュータブルなオブジェクトの場合は、オブジェクトが同一のまま(idが変わらないいまま)値だけを変更することができます。

x_list = [10, 11, 12, 13]
print(id(x))
>> 139800586264440

x_list[0] = 2
print(id(x))
>> 139800586264440 # idが同じ


注意すべき点

イミュータブルとミュータブルについて理解し、注意しなければいけないのは、「何が変わって、何が変わっていないのか」をよく理解しておかないと、バグを埋め込んでしまう可能性があるからです。

例えば、イミュータブルな文字列をコピーし、コピー先の文字列を変更しても、元の文字列は変わりません。

x_str = 'Apple'
x2_str = x_str
x2_str = x2_str + 'Store'

print(x_str)
>> Apple

print(x2_str)
>> AppleStore

しかし、ミュータブルなリストをコピーし、コピー先のリストを変更するとどうなるのでしょうか。

x_list = [10, 11, 12]
x2_list = x_list
x2_list[0] = 20

print(x_list)
>> [20, 11, 12]

print(x2_list)
>> [20, 11, 12]

コピー先のリストだけでなく、コピー元のリストも変更されます。

イメージしやすいように「コピー」という言葉を使いましたが、Pythonの = (代入式) は値の代入ではなく参照の代入になります。つまり見ているオブジェクト(id)は同じになります。イミュータブルな文字列は x2_str = x2_str + 'Store' のタイミングで新しいオブジェクトが生成されるため、x2_strx_str ではオブジェクトが異なります。

ミュータブルなオブジェクトとイミュータブルなオブジェクトでは、このような違いが発生するので、両方の性質を理解する必要があります。

同じ理由で、関数にミュータブルなオブジェクトを設定すると、関数に渡す変数自体が変更されてしまうため、Pythonではあまり好まれません。

x = [0, 1, 2, 3]

def test(a):
    a.append(9)

test(x)
print(x)
>> [0, 1, 2, 3, 9]


関連記事