スポンサーリンク

【Python入門】ミュータブルとイミュータブルとは?初心者でもわかる違いと注意点

Python入門
  1. 1. はじめに|Pythonでは「変えられる」かどうかが重要
  2. 2. ミュータブルとイミュータブルの違いとは?
    1. 🔹 ミュータブル(mutable)とは?
    2. 🔸 イミュータブル(immutable)とは?
    3. 🔍 代表的なミュータブルとイミュータブル
    4. 💡 なぜこの違いがあるの?
  3. 3. なぜこの違いが重要なのか?【バグの温床】
    1. 🔁 代入は「値」ではなく「参照」のコピー
    2. ✅ id()で確認してみよう
    3. 🚨 イミュータブルではどうなる?
    4. 🧠 この違いを知らないとどうなる?
    5. 💡 対策は?
  4. 4. 関数に渡すとどうなる?|引数の挙動を確認
    1. 🧊 イミュータブルなオブジェクトを渡す場合
    2. 🧪 ミュータブルなオブジェクトを渡す場合
    3. 🛡️ 安全に関数を使うための工夫
    4. 🧠 整理すると
  5. 5. 対策方法|安全なコードを書くために知っておこう
    1. ✅ 対策①:代入するときは「参照」がコピーされることを意識する
    2. ✅ 対策②:変更を加えたくないときは .copy() を使おう
    3. ✅ 対策③:複雑なデータ構造は copy.deepcopy() を使おう
    4. ✅ 対策④:関数の引数にミュータブルを渡すときは特に注意
    5. ✅ 対策⑤:読み取り専用ならタプル(tuple)を活用しよう
    6. 🧠 最後に覚えておきたいポイント
  6. 6. まとめ|覚えておきたいポイント
    1. 🎯 この記事のポイントまとめ
    2. あわせて読みたい
  7. よくある質問(Q&A)
    1. 関連投稿:

1. はじめに|Pythonでは「変えられる」かどうかが重要

Pythonを学びはじめると、リストや文字列、辞書など、いろんなデータ型を使うようになりますよね。

そのとき「リストの中身は書き換えられるのに、文字列は書き換えられないってどういうこと?」と疑問に思ったことはありませんか?

実はこれ、Pythonの世界ではとても大事なポイントなんです。

Pythonでは、データの型によって「変更できる」ものと「変更できない」ものに分かれています。
この性質は、それぞれ **ミュータブル(mutable)イミュータブル(immutable)**と呼ばれます。

  • ミュータブル:中身を自由に書き換えられる(例:リストや辞書)
  • イミュータブル:中身をあとから変更できない(例:文字列や数値)

「え、それってそんなに重要?」と思うかもしれませんが、この違いを知らずにコードを書くと、思いもよらないバグにつながることもあるんです!

この記事では、Python初心者でもわかるように、ミュータブルとイミュータブルの違いや注意点をやさしく解説します。
最後まで読めば、「変えられる」と「変えられない」の違いがしっかり理解できて、より安全で読みやすいPythonコードが書けるようになりますよ!

それでは、さっそく本題に入っていきましょう。




2. ミュータブルとイミュータブルの違いとは?

Pythonのオブジェクト(データ)は、大きく2つのタイプに分けることができます。それが「ミュータブル(mutable)」と「イミュータブル(immutable)」です。

🔹 ミュータブル(mutable)とは?

「あとから中身を変更できる」オブジェクトのことです。

例えば、リストや辞書、集合などがこれにあたります。

fruits = ["apple", "banana"]
fruits.append("orange")
print(fruits) # ['apple', 'banana', 'orange']

このように、fruitsというリストにappend()で要素を追加することで、元のリストが書き換わっていますよね。これがミュータブルな動きです。

🔸 イミュータブル(immutable)とは?

「中身を変更できない」オブジェクトのことです。

整数、浮動小数点、文字列、タプルなどが該当します。

text = "Hello"
text = text + " World"
print(text) # "Hello World"

この場合、実は「text」の中身が変わったように見えますが、新しい文字列オブジェクトが作られて、変数textがそれを参照し直しているだけなんです。

その証拠に、id()関数でオブジェクトのIDを確認してみると違いがわかります。

num = 10
print(id(num)) # 例: 140723586985264

num += 1
print(id(num)) # 例: 140723586985296(違うIDに!)

このように、**イミュータブルなオブジェクトは「変更」ではなく「新しいものを作って差し替えている」**んです。


🔍 代表的なミュータブルとイミュータブル

オブジェクトの型ミュータブル or イミュータブル
int, float, str, bool, tupleイミュータブル
list, dict, setミュータブル

この表はぜひ覚えておくと便利です!


💡 なぜこの違いがあるの?

イミュータブルなオブジェクトは、安全性とパフォーマンスを重視した設計になっています。たとえば、文字列や数値のように「変更されないことが前提」のものは、共有して使い回すことでメモリ効率がよくなります。

一方、リストや辞書のような「可変データ」は、柔軟な処理をするためにミュータブルになっています。




3. なぜこの違いが重要なのか?【バグの温床】

ミュータブルとイミュータブルの違いは、ただの知識ではなく、実際のコードのバグに直結する大事なポイントです。ここでは、なぜそれが重要なのか、具体例を交えて解説します。


🔁 代入は「値」ではなく「参照」のコピー

Pythonで変数に代入するとき、実は「値」をコピーしているわけではなく、「参照(=データのある場所)」をコピーしています。

x = [1, 2, 3]
y = x
y.append(4)
print(x) # [1, 2, 3, 4]

えっ、xを変更していないのに、中身が変わってる!?
……そうなんです。これがミュータブルオブジェクトの怖いところ

x = [1, 2, 3]のあとでy = xとしたとき、yx同じリスト(同じメモリ)を指している状態になっているので、どちらかで中身を変更すると、もう一方も一緒に変わってしまうんです。


✅ id()で確認してみよう

x = [1, 2, 3]
y = x

print(id(x)) # 例: 12345678
print(id(y)) # 同じID → 同じオブジェクトを参照

だから、片方をいじるともう片方も変わってしまうわけですね。


🚨 イミュータブルではどうなる?

一方、イミュータブルなオブジェクトでは、同じように見えても動きが違います。

a = 10
b = a
b += 1

print(a) # 10
print(b) # 11

この場合、b1を足したときに「新しいオブジェクトが作られて、それをbが参照するようになった」だけなので、aは無事です。


🧠 この違いを知らないとどうなる?

Python初心者がよくやってしまうのがこんなパターン:

def add_item(mylist):
mylist.append("new")

data = ["original"]
add_item(data)
print(data) # ['original', 'new'] ← あれ?関数内で変えたのに…

関数の中で変更したのに、元の変数まで変わっている!

これも、リストがミュータブルであり、関数に渡されたときも参照(メモリ上の場所)が引き継がれているからです。


💡 対策は?

こうしたバグを避けるには、以下のような方法があります:

  • list.copy()copy.deepcopy() を使って、別のオブジェクトを作る
  • 関数に渡すときは、元のデータを変えないように工夫する
  • そもそも、どの型がミュータブルか意識しながら設計する

✅ ポイント:リスト・辞書・集合は「変更される可能性がある」ので扱いに注意!

このように、「ミュータブルとイミュータブルの違い」は、Pythonコードの安全性・予測可能性に直結するとても大事なテーマです。




4. 関数に渡すとどうなる?|引数の挙動を確認

Pythonでは、関数に変数を渡すとき「値そのもの」ではなく「参照(オブジェクトの場所)」が渡されます。

このとき、渡されるオブジェクトがミュータブルかイミュータブルかによって、関数内の処理が元の変数に影響を与えるかどうかが変わってくるんです。


🧊 イミュータブルなオブジェクトを渡す場合

たとえば整数(int)や文字列(str)などのイミュータブルなオブジェクトを関数に渡したときは、関数内で「値を変更しているように見えても、実は新しいオブジェクトが作られている」だけなので、元の変数には影響しません

def add_one(x):
x = x + 1
print("関数内:", x)

num = 10
add_one(num)
print("関数外:", num)

実行結果:

関数内: 11
関数外: 10

上の例では、x + 1の計算で新しい数値(11)が生成されて、それをxに再代入しているだけなので、numには影響していません。


🧪 ミュータブルなオブジェクトを渡す場合

一方、リストや辞書などのミュータブルなオブジェクトを関数に渡した場合は要注意。関数内で中身を変更すると、それがそのまま元の変数にも反映されてしまいます

def add_item(mylist):
mylist.append("new")

data = ["original"]
add_item(data)
print("関数外:", data)

実行結果:

関数外: ['original', 'new']

これは、mylistdata同じリストオブジェクトを参照しているためです。


🛡️ 安全に関数を使うための工夫

「関数内で元のデータを変えたくない!」というときは、次のようにコピーを渡すようにすると安心です。

def add_item(mylist):
mylist.append("new")

original = ["apple"]
add_item(original.copy()) # 元のリストは変更されない!
print(original) # ['apple']

もっと複雑なデータ構造(リストの中にリストなど)の場合は、copy.deepcopy() を使うのがおすすめです。


🧠 整理すると

オブジェクトの型関数に渡したときの影響備考
イミュータブル(int, str, tupleなど)影響なし(新しい値が作られる)元の変数はそのまま
ミュータブル(list, dict, setなど)影響あり(中身が変更される)元の変数も変わる可能性あり!

✅ ポイント:関数に変数を渡すときは、そのオブジェクトの性質(変更できるかどうか)を意識しよう!




5. 対策方法|安全なコードを書くために知っておこう

ここまで読んで、「ミュータブルとイミュータブル、間違えて使うと危険そう…」と思った方も多いかもしれません。

でも大丈夫!Python初心者でもすぐに実践できる、安全にコードを書くためのコツをここで紹介します。


✅ 対策①:代入するときは「参照」がコピーされることを意識する

まずはこれをしっかり意識しましょう。

a = [1, 2, 3]
b = a # bはaと同じリストを参照
b.append(4)
print(a) # [1, 2, 3, 4] ← 変わっちゃってる!

こういった無意識の「参照コピー」は、知らないうちにバグの原因になります。


✅ 対策②:変更を加えたくないときは .copy() を使おう

元のデータを変更したくないときは、リストや辞書をコピーして使うのが基本です。

original = ["a", "b"]
safe_copy = original.copy()
safe_copy.append("c")
print(original) # ['a', 'b']
print(safe_copy) # ['a', 'b', 'c']

タプル(tuple)はイミュータブルなので、そもそも変更できません。


✅ 対策③:複雑なデータ構造は copy.deepcopy() を使おう

リストの中に辞書が入っているなど、ネストされた構造では .copy() だけでは不十分です。

import copy

nested = [{"a": 1}, {"b": 2}]
clone = copy.deepcopy(nested)
clone[0]["a"] = 999

print(nested) # [{'a': 1}, {'b': 2}]
print(clone) # [{'a': 999}, {'b': 2}]

copy.deepcopy() を使えば、中の中まで完全にコピーされるので安心です!


✅ 対策④:関数の引数にミュータブルを渡すときは特に注意

関数にリストや辞書などを渡すときは、元のオブジェクトが変更される可能性があると意識しておきましょう。

もし「元のデータを変更したくない」ときは、関数の前に .copy() を使うか、関数内でコピーを作るのが安全です。

def safe_add(mylist):
local_copy = mylist.copy()
local_copy.append("safe")
return local_copy

✅ 対策⑤:読み取り専用ならタプル(tuple)を活用しよう

「変更しないリスト」がほしいときは、listではなく**tuple(タプル)**を使うと安全です。

weekdays = ("Mon", "Tue", "Wed")
# weekdays[0] = "Sun" # ← これはエラーになる(変更不可)

タプルはイミュータブルなので、意図しない変更を防ぐことができます


🧠 最後に覚えておきたいポイント

  • ミュータブル(リスト・辞書・集合)は中身が変わる!特に関数や代入に注意!
  • コピーを使えば安全に使える
  • タプルやイミュータブルな型を使うと変更の心配がない

✅ まとめ:「その変数、変わってもいい?」と一度立ち止まるクセをつけよう。




6. まとめ|覚えておきたいポイント

この記事では、Pythonにおける「ミュータブル」と「イミュータブル」の違いについて、初心者にもわかりやすく解説しました。

最初は少し難しく感じたかもしれませんが、この違いを理解することで、意図しないデータの変更やバグを防げるようになります!


🎯 この記事のポイントまとめ

  • **ミュータブル(mutable)**は「中身を変更できる」オブジェクト(例:list, dict, set
  • **イミュータブル(immutable)**は「中身を変更できない」オブジェクト(例:int, str, tuple
  • =による代入はオブジェクトの参照(場所)をコピーする
  • ミュータブルなオブジェクトを関数に渡すと、中身が変更される可能性がある
  • 元のデータを守るには .copy()copy.deepcopy() を使う
  • 「変更させたくないデータ」は tuple などイミュータブル型で表現しよう

Pythonを書くときは「この変数、他の場所で変更されたら困る?」という視点を持ってみてください。

ちょっとした意識の差で、バグのない読みやすいコードが書けるようになりますよ!


あわせて読みたい

ミュータブル・イミュータブルをしっかり理解したら、Python初心者がつまずきやすいエラーや代入の仕組みについても学んでおくと安心です。

以下の記事もぜひチェックしてみてください!



よくある質問(Q&A)

Q
listはミュータブル、tupleはイミュータブルって覚えるだけでOKですか?
A

はい、大まかにはそれでOKです。ただし、辞書(dict)や集合(set)もミュータブルなので、どの型が変更できるかを意識して使うことが大切です。

Q
copy()deepcopy()の違いはなんですか?
A

copy()浅いコピーで、ネストされたオブジェクトの中身まではコピーされません。
一方、deepcopy()中の中まで全部コピーするので、より安全です。

Q
なぜ文字列(str)はイミュータブルなのですか?
A

Pythonでは文字列を頻繁に使うため、イミュータブルにしておくことでメモリ効率が良くなるという設計になっています。また、安全性も高まります

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク