このページで解説している内容は、以下の 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プログラム内でデータを効率的かつ安全に扱うことができるようになります。次のコンテンツでは、インデックスを使った文字の取り出しについて詳しく解説していきます。ぜひ、実際にコードを書きながら、ミュータブルとイミュータブルの概念を深く理解してください。