Pythonの辞書(dict
)を使っているとき、「元のデータを変更せずに、コピーして使いたい!」という場面はよくあります。
でも、「=
で代入したら両方が変わってしまった!」「どれが正しいコピー方法かわからない…」
そんな悩みを持つ方向けに、この記事では辞書をコピーする4つの方法と、それぞれの違い・注意点を丁寧に説明していきます。
間違いやすい代入(コピーにならない!)

よくある間違い
original = {"name": "田中", "age": 25}
copy_data = original # これは間違い!
copy_data["age"] = 30
print(original["age"]) # 結果: 30 😱
何が起きた?
copy_data = original
では、コピーが作られませんcopy_data
とoriginal
は同じ辞書を指しています- どちらを変更しても、両方に影響します
図で理解:
original ──┐
├── {"name": "田中", "age": 25}
copy_data ─┘
まとめ
=
は「コピー」ではなく「参照の共有」- 元のデータを守りたいときは使えません
正しいコピー方法①:dict.copy()
基本的な使い方
original = {"name": "田中", "age": 25}
copy_data = original.copy() # 正しいコピー
copy_data["age"] = 30
print(original["age"]) # 結果: 25 🎉
print(copy_data["age"]) # 結果: 30
説明:
copy()
メソッドは浅いコピー(shallow copy)を作ります- 辞書の中身が単純な値(文字列、数値など)なら、これで十分です
図で理解:
original ── {"name": "田中", "age": 25}
copy_data ── {"name": "田中", "age": 30}
実用例:
# 設定の初期値をベースに、ユーザー設定を作る
default_settings = {"theme": "light", "font_size": 12, "auto_save": True}
user_settings = default_settings.copy()
user_settings["theme"] = "dark"
print(default_settings) # 結果: {"theme": "light", "font_size": 12, "auto_save": True}
print(user_settings) # 結果: {"theme": "dark", "font_size": 12, "auto_save": True}
正しいコピー方法②:dict()コンストラクタ

使い方
original = {"name": "田中", "age": 25}
copy_data = dict(original) # copy()と同じ効果
copy_data["age"] = 30
print(original["age"]) # 結果: 25
説明:
dict()
を使っても、copy()
と同じ浅いコピーができます- どちらを使うかは好みの問題です
使い分けの例:
# 書き方1: copy()メソッド
copy1 = original.copy()
# 書き方2: dict()コンストラクタ
copy2 = dict(original)
# 書き方3: 辞書リテラル(Python 3.5以降)
copy3 = {**original}
正しいコピー方法③:copyモジュール(浅いコピー)
使い方
import copy
original = {"name": "田中", "age": 25}
shallow_copy = copy.copy(original)
shallow_copy["age"] = 30
print(original["age"]) # 結果: 25
説明:
copy.copy()
は、辞書以外のデータ型でも使える汎用的な方法です- 辞書の場合は
dict.copy()
と同じ動作をします
どんなときに使う?
import copy
# 辞書だけでなく、リストやカスタムクラスでも使える
my_list = [1, 2, 3]
copied_list = copy.copy(my_list)
class Person:
def __init__(self, name):
self.name = name
person = Person("田中")
copied_person = copy.copy(person)
正しいコピー方法④:copy.deepcopy(深いコピー)

なぜ深いコピーが必要?
まず、浅いコピーの問題点を見てみましょう:
# 辞書の中に辞書がある(ネスト構造)
original = {
"user": {"name": "田中", "age": 25},
"settings": {"theme": "light"}
}
# 浅いコピーでは内側の辞書は共有される
shallow_copy = original.copy()
shallow_copy["user"]["age"] = 30 # 内側の辞書を変更
print(original["user"]["age"]) # 結果: 30 😱(元も変わってしまう)
なぜこうなる? 浅いコピーでは、外側の辞書はコピーされますが、内側の辞書は同じものを共有してしまいます。
図で理解:
original ── {"user": ──┐, "settings": ──┐}
│ │
shallow_copy ── {"user": ──┘, "settings": ──┘}
│ │
{"name": "田中", {"theme": "light"}
"age": 30}
深いコピーの使い方
import copy
original = {
"user": {"name": "田中", "age": 25},
"settings": {"theme": "light"}
}
# 深いコピーで完全に別のコピーを作る
deep_copy = copy.deepcopy(original)
deep_copy["user"]["age"] = 30
print(original["user"]["age"]) # 結果: 25 🎉(元は変わらない)
print(deep_copy["user"]["age"]) # 結果: 30
図で理解:
original ── {"user": ── {"name": "田中", "age": 25}, "settings": ── {"theme": "light"}}
deep_copy ── {"user": ── {"name": "田中", "age": 30}, "settings": ── {"theme": "light"}}
実用例:
# ゲームの設定をプレイヤーごとにカスタマイズ
default_config = {
"player": {"name": "", "level": 1},
"graphics": {"resolution": "1920x1080", "quality": "high"},
"controls": {"jump": "space", "move": "wasd"}
}
# プレイヤー1の設定
player1_config = copy.deepcopy(default_config)
player1_config["player"]["name"] = "太郎"
player1_config["graphics"]["quality"] = "low"
# プレイヤー2の設定
player2_config = copy.deepcopy(default_config)
player2_config["player"]["name"] = "花子"
# 元の設定は変わらない
print(default_config["player"]["name"]) # 結果: ""
コピー方法の比較表
方法 | コピーの深さ | 特徴 | ネスト構造への対応 | 使う場面 |
---|---|---|---|---|
= (代入) | なし | コピーではない、参照共有 | × | 使わない |
.copy() | 浅い | シンプル、辞書専用 | × | 単純な辞書 |
dict() | 浅い | 同上、書き方が違う | × | 単純な辞書 |
copy.copy() | 浅い | 辞書以外でも使える | × | 汎用的に使いたい |
copy.deepcopy() | 深い | 完全に独立したコピー | ○ | ネスト構造がある |
よくある注意点とトラブル対策

注意点1:浅いコピーではネストされたオブジェクトは共有される
original = {
"fruits": ["apple", "banana"],
"user": {"name": "田中"}
}
# 浅いコピーの問題
shallow_copy = original.copy()
shallow_copy["fruits"].append("orange") # リストに要素追加
shallow_copy["user"]["name"] = "佐藤" # 辞書の値変更
print(original["fruits"]) # 結果: ["apple", "banana", "orange"] 😱
print(original["user"]["name"]) # 結果: "佐藤" 😱
対策:
# 深いコピーを使う
deep_copy = copy.deepcopy(original)
deep_copy["fruits"].append("orange")
deep_copy["user"]["name"] = "佐藤"
print(original["fruits"]) # 結果: ["apple", "banana"] 🎉
print(original["user"]["name"]) # 結果: "田中" 🎉
注意点2:copy.deepcopy()は重い処理
import time
import copy
# 大きな辞書の例
large_dict = {}
for i in range(10000):
large_dict[f"key_{i}"] = {"data": list(range(100))}
# 時間を測定
start_time = time.time()
deep_copy = copy.deepcopy(large_dict)
end_time = time.time()
print(f"深いコピーにかかった時間: {end_time - start_time:.3f}秒")
対策:
- 本当に必要な場合のみ
deepcopy()
を使う - データ構造を工夫して、ネストを浅くする
注意点3:JSONを使った簡易的な深いコピー
import json
original = {
"user": {"name": "田中", "age": 25},
"settings": {"theme": "light"}
}
# JSONを使った深いコピー
json_copy = json.loads(json.dumps(original))
json_copy["user"]["age"] = 30
print(original["user"]["age"]) # 結果: 25 🎉
制限事項:
- JSONで表現できるデータのみ(文字列、数値、リスト、辞書、真偽値、None)
- 関数やカスタムクラスのインスタンスは使えない
- 日付オブジェクトなども使えない
使える場面:
# これはOK
simple_data = {
"name": "田中",
"age": 25,
"hobbies": ["読書", "映画"],
"settings": {"notifications": True}
}
# これはエラーになる
import datetime
complex_data = {
"name": "田中",
"created": datetime.datetime.now(), # 日付オブジェクト
"process": lambda x: x * 2 # 関数
}
どの方法を選ぶべき?フローチャート
辞書をコピーしたい
↓
辞書の中にリストや辞書が含まれている?
↓ ↓
はい いいえ
↓ ↓
copy.deepcopy() dict.copy()
を使う を使う
実践的な使用例
例1:設定ファイルの管理
import copy
# デフォルト設定
default_config = {
"database": {
"host": "localhost",
"port": 5432,
"timeout": 30
},
"logging": {
"level": "INFO",
"file": "app.log"
}
}
# 本番環境用の設定
production_config = copy.deepcopy(default_config)
production_config["database"]["host"] = "prod-server.com"
production_config["logging"]["level"] = "ERROR"
# テスト環境用の設定
test_config = copy.deepcopy(default_config)
test_config["database"]["host"] = "test-server.com"
test_config["logging"]["level"] = "DEBUG"
# デフォルト設定は変わらない
print(default_config["database"]["host"]) # 結果: "localhost"
例2:ユーザープロフィールの管理
import copy
# ユーザープロフィールのテンプレート
profile_template = {
"personal": {
"name": "",
"age": 0,
"email": ""
},
"preferences": {
"language": "ja",
"timezone": "Asia/Tokyo",
"notifications": True
},
"history": []
}
# 新しいユーザーのプロフィールを作成
def create_user_profile(name, age, email):
profile = copy.deepcopy(profile_template)
profile["personal"]["name"] = name
profile["personal"]["age"] = age
profile["personal"]["email"] = email
return profile
# 使用例
user1 = create_user_profile("田中太郎", 25, "tanaka@example.com")
user2 = create_user_profile("佐藤花子", 30, "sato@example.com")
# 個別にカスタマイズ
user1["preferences"]["language"] = "en"
user2["history"].append("ログイン")
# テンプレートと他のユーザーは影響を受けない
print(profile_template["preferences"]["language"]) # 結果: "ja"
print(user2["preferences"]["language"]) # 結果: "ja"
まとめ
シーン | おすすめの方法 | 理由 |
---|---|---|
単純な辞書のコピー | .copy() または dict() | 高速で簡単 |
ネスト構造がある辞書 | copy.deepcopy() | 完全に独立したコピー |
軽量で一時的なコピー | json.loads(json.dumps()) | シンプルなデータのみ |
絶対に避ける | = (代入) | コピーにならない |
コメント