Categories: Python

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

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

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

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

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

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

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

int型はイミュータブルなので同じオブジェクトのまま値を変更することができません。以下のコードでは、値を変更しているかに見えますが単に異なるオブジェクトを代入しているに過ぎない。

num = 1

num = 2

IDを比較することで同じオブジェクトなのか確認することができます。参考 → 「オブジェクトの識別値(ID)について

num = 1
id1 = id(num)

num = 2
id2 = id(num)
print(id1 == id2)

実行結果

False

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

プロパティから直接値を書き換えようとするとAttributeErrorが発生します。

num = 1

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

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

リストなどのミュータブルなオブジェクトは、以下のように同じオブジェクトのまま値だけ変更することができます。

l = [1, 2]
id1 = id(l)

l.append(3)
id2 = id(l)

print(l)           # [1, 2, 3]
print(id1 == id2)  # True

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

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

  • 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]

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

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

まとめ

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

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

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

ゆうまる

独学でプログラミングを勉強しているおじさん。いろんな言語を勉強したが浅く広くなためあまり仕事につながらない。また忘れっぽいため自分のブログを備忘録としても使っている。産まれてこのかたずっとネコを飼ってる生粋のネコ派。最近お腹が出てきて筋トレに奮闘中!

View Comments

Recent Posts

【Dart】コンストラクタのデフォルト引数について

Dartのコンストラクタのデフォルト引数…

2週間 ago

【Unity】有料アセットを無料で手に入れる方法

この記事では、Unityの有料アセットを…

4か月 ago

【Python】任意の秒数だけ処理を一時停止する方法【sleep()関数】

この記事では、Pythonで任意の秒数だ…

1年 ago

【Python】Wordの文書の新規作成と読み書き

この記事では、Pythonを使ってWor…

1年 ago

【Python】メタクラスって結局なんなの?

この記事では、Pythonのメタクラスに…

1年 ago