Pythonにおけるmutable(可変)とimmutable(不変)の違いは、オブジェクトの内容を変更できるかどうかという点にあります。可変と不変の違いを理解することで、バグを防止したり、適切なデータ構造を選択したりすることができます。
mutable(可変)とは?
オブジェクトの内容を変更することが可能。例えば、リストや辞書のように一度作成した後でも、内部の要素を変更できるオブジェクトが該当します。
代表的なmutableなオブジェクト
- list(リスト)
- dict(辞書)
- set(集合)
- bytearray
# リストの要素を変更する
my_list = [1, 2, 3]
print(id(my_list)) # 140007375707712
my_list[0] = 100 # 1 → 100 に変更
print(id(my_list)) # 140007375707712
print(my_list) # [100, 2, 3]
my_listはリストで、要素を直接変更することができます。オブジェクト(140007375707712)は変わっていないです。
immutable(不変)とは?
オブジェクトを一度作成した後、その内容を変更できない。例えば、文字列やタプルのように要素を変更する操作が許されないオブジェクトが該当します。
代表的なimmutableなオブジェクト
- str(文字列)
- tuple(タプル)
- int(整数型)
- float(浮動小数点数型)
- frozenset(凍結された集合)
# 文字列の内容を変更しようとする
my_string = "hello"
# my_string[0] = 'H' # これはエラーになる
print(id(my_string)) # 140426410082544
# 新しい文字列を作成する(元の文字列は変更されない)
my_string = "H" + my_string[1:]
print(id(my_string)) # 140426410083248
print(my_string) # "Hello"
文字列my_stringは不変で、部分的に内容を変更することはできません。代わりに新しい文字列を生成する形になります。オブジェクトID(140426410082544⇒140426410083248)も変わった。
可変と不変の違いが重要になる場面
- 関数の引数の扱い
可変オブジェクトを関数に渡すと、元のオブジェクトが直接変更される場合があります。
例:可変オブジェクトを関数に渡した例
def add_item(lst):
lst.append(100)
my_list = [1, 2, 3]
add_item(my_list)
print(my_list) # [1, 2, 3, 100]
関数add_itemにリストmy_listを渡したところ、元のリストが直接変更されました。
例:不変オブジェクトを関数に渡した例
def add_value(num):
num += 100
my_num = 50
add_value(my_num)
print(my_num) # 50(変更されない)
- 辞書のキーとしての使用
immutableなオブジェクトは辞書のキーに使用できますが、mutableなオブジェクトは使用できません。
例:タプルを辞書のキーに使う
my_dict = { (1, 2): "point A" }
print(my_dict[(1, 2)]) # "point A"
例:リストを辞書のキーに使おうとするとエラーになる
# my_dict = { [1, 2]: "point B" } # TypeError: unhashable type: 'list'
リストはmutableなため、辞書のキーには使えません。一方でタプルはimmutableなので、辞書のキーとして使えます。
まとめ
特性 | mutable(可変) | immutable(不変) |
---|---|---|
代表例 | リスト、辞書、集合 | 文字列、タプル、整数 |
内容の変更 | 可能 | 不可能 |
辞書のキーとして使用 | 不可 | 可能 |
関数内での影響 | 元のオブジェクトが変更される | 元のオブジェクトは影響なし |