このページで解説している内容は、以下の YouTube 動画の解説で見ることができます。
【Python入門】ミュータブルとイミュータブル

ミュータブルとイミュータブル
Pythonプログラミングにおいて、ミュータブル(mutable)とイミュータブル(immutable)は、オブジェクトの性質を理解する上で重要な概念です。これらの概念を正しく理解することで、データの扱いやメモリ管理、プログラムの効率性を向上させることができます。ここでは、ミュータブルとイミュータブルの違い、具体的な例、メモリ上でのオブジェクトの取り扱い方法について詳しく解説します。

プログラムのダウンロード
「ダウンロード」から、JupyterLab で実行できるサンプルプログラムがダウンロードできます。ファイルは、ESET Endpoint Securityでウイルスチェックをしておりますが、ダウンロードとプログラムの実行は自己責任でお願いいたします。
1.ミュータブルとイミュータブルとは
ミュータブル(mutable)なオブジェクトとは、その内容を変更することができるオブジェクトのことです。一方、イミュータブル(immutable)なオブジェクトは、一度作成された後にその内容を変更することができないオブジェクトを指します。
Pythonの組み込み型には、ミュータブルな型とイミュータブルな型が存在します。代表的なものを以下の表にまとめました。
オブジェクトの種類 | ミュータブル | イミュータブル |
---|---|---|
数値(int, float) | × | ○ |
文字列(str) | × | ○ |
リスト(list) | ○ | × |
タプル(tuple) | × | ○ |
辞書(dict) | ○ | × |
セット(set) | ○ | × |
バイト列(bytes) | × | ○ |
ポイント
- ミュータブルなオブジェクトは、その場で内容を変更できるため、メモリの節約や処理速度の向上につながる場合があります。
- イミュータブルなオブジェクトは、安全性が高く、予期せぬ変更を防ぐことができます。
2.イミュータブルなオブジェクトの例:文字列
文字列(str)は、Pythonにおけるイミュータブルなオブジェクトの代表例です。文字列は一度作成されると、その内容を直接変更することはできません。しかし、演算子やメソッドを使用して新しい文字列を生成することは可能です。
2.1. 文字列の連結とイミュータブル性
文字列を連結する際、元の文字列は変更されず、新しい文字列が生成されます。以下の例を見てみましょう。
サンプルプログラム
# 文字列の連結前
data = "Data:"
print(data) # 出力: Data:
# 文字列を連結
data += " Science"
print(data) # 出力: Data: Science
出力結果
Data:
Data: Science
解説
- 最初に変数
data
に"Data:"
を代入します。 data += " Science"
は、data = data + " Science"
と同等であり、新しい文字列"Data: Science"
が生成され、data
に再代入されます。- 元の
"Data:"
という文字列オブジェクトは変更されず、新しい文字列オブジェクトがメモリ上に作成されます。
2.2. メモリ上でのオブジェクトの扱い
以下の図は、文字列の連結前後のメモリ上のオブジェクトと変数の参照を示しています。
文字列の連結前
メモリ上のオブジェクト | 参照先 | メモリ上の変数(一覧) |
---|---|---|
アドレス: 3000000型 文字列 (String) 値: 'Data:' | ← | 変数名: data 参照先: アドレス 3000000 |
文字列の連結後
メモリ上のオブジェクト | 参照先 | メモリ上の変数(一覧) |
---|---|---|
アドレス: 3000000型 文字列 (String) 値: 'Data:' | ||
アドレス: 4000000型 文字列 (String) 値: 'Data: Science' | ← | 変数名: data 参照先: アドレス 4000000 |
ポイント
data
変数は、連結前はアドレス3000000
のオブジェクトを参照していましたが、連結後は新しく生成されたアドレス4000000
のオブジェクトを参照します。- 元の
'Data:'
という文字列オブジェクトは、どの変数からも参照されなくなり、ガベージコレクションの対象となります。
2.3. パフォーマンスへの影響
文字列の連結を頻繁に行うと、新しいオブジェクトの生成が繰り返され、メモリ使用量や処理時間が増加します。以下の例では、文字列を +=
演算子で大量に連結する場合のパフォーマンスについて説明します。
サンプルプログラム
※print(result)
でresult
の内容は出力していません。実行するとフリーズするためです。
# 複数回の連結操作
result = ""
for i in range(1000000):
result += "a"
解説
- このプログラムでは、空文字列に対して
+=
演算子を使用して"a"
を1,000,000回連結しています。 - 各
+=
操作ごとに新しい文字列オブジェクトが生成されるため、処理時間が長くなり、メモリ使用量も増加します。 - 大量の連結操作が必要な場合は、リストに文字列を追加し、最後に
join()
メソッドを使用して一度に連結する方法が推奨されます。
効率的な連結方法の例
サンプルプログラム
※print(result)
でresult
の内容は出力していません。実行するとフリーズするためです。
# 効率的な連結方法
parts = []
for i in range(1000000):
parts.append("a")
result = "".join(parts)
解説
- リスト
parts
に"a"
を追加し、最後にjoin()
メソッドで一度に連結します。 - この方法では、新しいオブジェクトの生成が最小限に抑えられ、パフォーマンスが向上します。
3.ミュータブルなオブジェクトの例:リスト
リスト(list)は、Pythonにおけるミュータブルなオブジェクトの代表例です。リストは、作成後にその内容を自由に変更することができます。
3.1. リストの操作とミュータブル性
リストに要素を追加、削除、変更することが可能です。以下の例を見てみましょう。
サンプルプログラム
# リストの操作前
fruits = ["apple", "banana", "cherry"]
print(fruits) # 出力: ['apple', 'banana', 'cherry']
# 要素の追加
fruits.append("date")
print(fruits) # 出力: ['apple', 'banana', 'cherry', 'date']
# 要素の変更
fruits[1] = "blueberry"
print(fruits) # 出力: ['apple', 'blueberry', 'cherry', 'date']
# 要素の削除
fruits.remove("cherry")
print(fruits) # 出力: ['apple', 'blueberry', 'date']
出力結果
['apple', 'banana', 'cherry']
['apple', 'banana', 'cherry', 'date']
['apple', 'blueberry', 'cherry', 'date']
['apple', 'blueberry', 'date']
解説
- 変数
fruits
にリスト["apple", "banana", "cherry"]
を代入します。 fruits.append("date")
により、リストに"date"
が追加されます。fruits[1] = "blueberry"
により、インデックス1の要素"banana"
が"blueberry"
に変更されます。fruits.remove("cherry")
により、リストから"cherry"
が削除されます。- リストはミュータブルであるため、これらの操作によってリストの内容が直接変更されます。
3.2. メモリ上でのオブジェクトの扱い
以下の図は、リストの操作前後のメモリ上のオブジェクトと変数の参照を示しています。
リストの操作前
メモリ上のオブジェクト | 参照先 | メモリ上の変数(一覧) |
---|---|---|
アドレス: 5000000型 リスト (List) 値: ['apple', 'banana', 'cherry'] | ← | 変数名: fruits 参照先: アドレス 5000000 |
リストの操作後
メモリ上のオブジェクト | 参照先 | メモリ上の変数(一覧) |
---|---|---|
アドレス: 5000000型 リスト (List) 値: ['apple', 'blueberry', 'date'] | ← | 変数名: fruits 参照先: アドレス 5000000 |
ポイント
- リストはミュータブルであるため、要素の追加や変更が直接リストオブジェクトに反映されます。
- 新しいオブジェクトの生成は不要であり、変数
fruits
は同じオブジェクトを参照し続けます。
4.ミュータブルとイミュータブルの使い分け
ミュータブルとイミュータブルの性質を理解することで、適切なデータ型を選択し、効率的なプログラムを作成することができます。
4.1. イミュータブルなオブジェクトの利点
- 安全性の向上:オブジェクトが変更されないため、予期せぬ変更によるバグを防ぐことができます。
- ハッシュ可能:イミュータブルなオブジェクトはハッシュ可能であり、辞書のキーやセットの要素として使用できます。
- パフォーマンスの最適化:変更されないため、内部での最適化が可能です。
4.2. ミュータブルなオブジェクトの利点
- 柔軟なデータ操作:オブジェクトの内容を直接変更できるため、データの更新や加工が容易です。
- メモリの効率化:新しいオブジェクトを生成せずに内容を変更できるため、大規模なデータ操作においてメモリの節約につながります。
- 動的なデータ構造の構築:リストや辞書など、動的に要素を追加・削除できるデータ構造を実現できます。
4.3. 適切なデータ型の選択
プログラムの要件に応じて、ミュータブルとイミュータブルのオブジェクトを使い分けることが重要です。
要件 | 推奨されるデータ型 |
---|---|
データが変更されない | 数値(int, float)、文字列(str)、タプル(tuple)、バイト列(bytes) |
データが頻繁に変更される | リスト(list)、辞書(dict)、セット(set) |
辞書のキーやセットの要素として使用 | イミュータブルな型(数値、文字列、タプル) |
動的なデータ構造の構築 | リスト(list)、辞書(dict)、セット(set) |
ポイント
- 変更が不要なデータにはイミュータブルな型を使用し、データの安全性とパフォーマンスを向上させる。
- データが頻繁に変更される場合はミュータブルな型を使用し、柔軟なデータ操作を可能にする。
4.ミュータブルとイミュータブルのまとめ
特徴 | ミュータブル | イミュータブル |
---|---|---|
変更の可否 | 変更可能 | 変更不可 |
主なデータ型 | リスト(list)、辞書(dict)、セット(set) | 数値(int, float)、文字列(str)、タプル(tuple)、バイト列(bytes) |
ハッシュ可能性 | × | ○ |
メモリ効率 | 変更に伴うメモリ再割り当てが不要 | 変更時に新しいオブジェクトが生成される |
使用例 | 動的なデータ操作、データの更新が必要な場合 | データの安全性が重要な場合、辞書のキーやセットの要素として使用 |
ポイント
- ミュータブルとイミュータブルの違いを理解し、適切なデータ型を選択することで、効率的で安全なプログラムを作成できます。
- それぞれの性質に応じた使い方を意識することで、バグの発生を防ぎ、パフォーマンスを最適化することが可能です。
まとめ
ここでは、Pythonにおけるミュータブルとイミュータブルについて学びました。
- ミュータブルとイミュータブルとは:オブジェクトの変更可能性に基づく分類。
- イミュータブルなオブジェクトの例:文字列(str)や数値(int, float)など。
- ミュータブルなオブジェクトの例:リスト(list)や辞書(dict)など。
- 使い分けのポイント:データの変更が必要かどうかに応じて、適切なデータ型を選択する重要性。
- 具体的な例とメモリ上での扱い:オブジェクトの参照と変更がメモリに与える影響についての理解。
- まとめ表:ミュータブルとイミュータブルの特徴を比較。
これらの知識を基に、Pythonプログラム内でデータを効率的かつ安全に扱うことができるようになります。次のコンテンツでは、インデックスを使った文字の取り出しについて詳しく解説していきます。ぜひ、実際にコードを書きながら、ミュータブルとイミュータブルの概念を深く理解してください。