Pythonの辞書(dict)をコピーする方法と注意点まとめ

ここでは、Pythonで辞書をコピーする方法についてまとめています。

具体的には、

  • ミュータブルなオブジェクトである辞書を代入でコピーすることの弊害
  • copy()メソッドを使った辞書のコピー方法
  • dict.fromkeys()関数を使って、リストのキーだけをコピーする方法

の3つを解説しています。

ぜひ、参考にして頂ければ嬉しく思います。

目次

1. 辞書をコピーしたい時は代入は使わないこと

Pythonで既存の辞書をコピーして、新しい辞書を作る時にありがちなミスが、「new_dict = old_dict」というように、「新しい辞書に既存の辞書を代入してしまう」というものです。

辞書はイミュータブルなオブジェクトです。そのため、この方法では、新しくコピーした(つもり)の辞書に変更を加えると、元のリストにまで同じ変更が加えられてしまうという問題が起きます。

以下の例をご覧ください。

In [1]:
#dict1を作ります。
dict1 = {"red":1, "blue":2, "yellow":3}
 
#dict2にdict1を代入します。
dict2 = dict1
 
#dict2の値を変更します。
dict2["red"] = 4
 
#dict2を確認しましょう。
dict2
Out[1]:
{'blue': 2, 'red': 4, 'yellow': 3}

一見問題ないように見えますが、実は、このとき元の辞書(dict1)も変更されてしまっています。

In [2]:
#この時、辞書1(dict1)にも変更が反映されてしまいます。
dict1
Out[2]:
{'blue': 2, 'red': 4, 'yellow': 3}

なぜ、このようなことが起きてしまうのでしょうか?

それは、dict1と、それを代入して作ったdict2は、同一オブジェクトとなり、一方に加えた変更は、他方にも影響してしまうからです。ミュータブルなオブジェクトには、常にこの問題が付きまといますので、辞書やリストは、新しい変数に代入してコピーするという癖をつけないようにした方がよいです。

ミュータブルなオブジェクトとイミュータブルなオブジェクトの違いと、双方を扱うときの注意点は、「Pythonのリストとタプルの違いと使い分け」でも、リストとタプルを比較して解説しています。併せてご覧いただくと、理解が深まるでしょう。

このような問題を防ぐためには、ミュータブルなオブジェクトをコピーする時は、copy()メソッドを使うことを癖づけると良いでしょう。

2. 辞書のコピーにはcopy()メソッドを使う

copy()メソッドで作った新しい辞書は、元となった辞書と別のオブジェクトになります。そのため、上記のような問題は起こりません。次のように書きます。

In [0]:
新しい辞書 = コピー元の辞書.copy()

引数には特に何も入力する必要はありません。実際に見てみましょう。

In [1]:
#辞書1(dict1)を作ります。
dict1 = {"red":1, "blue":2, "yellow":3}
 
#copy()メソッドで辞書を作ります。
dict2 = dict1.copy()
 
#dict2の値を変更します。
dict2["red"] = 4
 
#dict2を確認しましょう。
dict2
Out[1]:
{'blue': 2, 'red': 4, 'yellow': 3}

この時、dict1 と dict2 は別のオブジェクトなので、元の辞書である dict1 には影響はありません。

In [2]:
#dict1に変更は反映されません。
dict1
Out[2]:
{'blue': 2, 'red': 1, 'yellow': 3}

せっかく沢山書いたコードが、辞書のミュータビリティが原因で動かないとなると、その原因を特定して修正する手間は、かなりのものになります。そのような状況を防ぐためにも、ミュータブルなオブジェクトである辞書をコピーしたい時は、copy()メソッドを使いましょう。

3. ある辞書のキーだけコピーするにはdict.fromkeys()を使う

ある辞書のキーだけをコピーしたい場合は、dict.fromkeys()関数が便利です。次のように書きます。

In [0]:
新しい辞書 = dict.fromkeys(辞書, 値)

実際に見てみましょう。

In [1]:
#dict1を作ります。
dict1 = {"red":1, "blue":2, "yellow":3}
 
#dict.fromkeys()でキーをコピーしたdict2を作ります。
dict2 = dict.fromkeys(dict1, 0)
 
#確認しましょう。
dict2
Out[1]:
{'blue': 0, 'red': 0, 'yellow': 0}

値を指定しない場合は、キーの値は空(None)になります。

In [1]:
#辞書1(dict1)を作ります。
dict1 = {"red":1, "blue":2, "yellow":3}
 
#dict.fromkeys()でキーをコピーした辞書2(dict2)を作ります。
dict2 = dict.fromkeys(dict1)
 
#確認しましょう。
dict2
Out[1]:
{'blue': None, 'red': None, 'yellow': None}

知っておくと便利なので、頭の片隅に入れておいて頂ければと思います。

4. まとめ

ミュータブルなオブジェクトである辞書やリストを、コピーする際は、代入による方法は避けて、copy()メソッドを使うように癖づけておきましょう。

また、ミュータブルなオブジェクトと、イミュータブルなオブジェクトの違いを、しっかりと理解しておけば、様々なところで最適な選択をできるようになると思います。コードを書きながら、少しずつ理解を深められるように、意識できればとても良いと思います。

なお辞書の場合はcopy()メソッドで問題ありませんが、リストの場合は、「浅いコピー」と「深いコピー」という概念を知っておかなければ、後で大変な思いをする可能性があります。

Pythonのリストのコピー方法と注意点」でしっかりと確認しておきましょう。



よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメント一覧 (1件)

  • >1. 辞書をコピーしたい時は代入は使わないこと
    にて、
    >辞書はイミュータブルなオブジェクトです。

    となっています。ミュータブルの間違いでしょうか。

    また、本記事で示されている例であれば問題になりませんが、辞書の中にミュータブルオブジェクトを含めた場合、copy()だけでは完全にコピーできません。リストだけでなく辞書でも深いコピーを使う必要があります。

    問題になる例:
    dict1 = {“x”:[1,2,3]}
    dict2 = dict1.copy()
    dict2[“x”][0] = 100
    print(dict1[“x”]) # [100,2,3]
    print(dict2[“x”]) # [100,2,3]

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次
閉じる