Python - copy と deepcopy と dict

投稿日: 2023/02/02
更新日: 2023/02/02
シェア:

URL copied!


概要

変数を他の変数にコピーする時に気をつけたいこと。

やってみた

import copy

# case1
a = {1: {10: 100, 20: 200}, 2: 20}
b = a.copy()
b[1][10] = 999
b[2] = 99
print(f"{a=} / {b=}")
# a={1: {10: 999, 20: 200}, 2: 20} / b={1: {10: 999, 20: 200}, 2: 99}

# case2
a = {1: {10: 100, 20: 200}, 2: 20}
b = copy.copy(a)
b[1][10] = 999
b[2] = 99
print(f"{a=} / {b=}")
# a={1: {10: 999, 20: 200}, 2: 20} / b={1: {10: 999, 20: 200}, 2: 99}

# case3
a = {1: {10: 100, 20: 200}, 2: 20}
b = copy.deepcopy(a)
b[1][10] = 999
b[2] = 99
print(f"{a=} / {b=}")
# a={1: {10: 100, 20: 200}, 2: 20} / b={1: {10: 999, 20: 200}, 2: 99}

# case4
a = {1: {10: 100, 20: 200}, 2: 20}
b = a
b[1][10] = 999
b[2] = 99
print(f"{a=} / {b=}")
# a={1: {10: 999, 20: 200}, 2: 99} / b={1: {10: 999, 20: 200}, 2: 99}

表1:コピー元(a)の変化について

case 関数 val
(a[2])
dict のなかの val
(a[1][10])
1 ビルトインメソッド 変化なし 変化あり
2 copy.copy() 変化なし 変化あり
3 copy.deepcopy() 変化なし 変化なし
4 直接代入 変化あり 変化あり

考察

使用用途に応じて使い分ける必要がある。
今後とも dict の中に dict が入ってこない処理に関してはビルトインメソッドを使って良いだろう。しかし、どんな dict が入ってくるかわからない関数では最初から deepcopy を使っておくと安心である。

おまけ:keyだけコピーしたい場合

fromkeys という便利なビルトインメソッドが存在する。

dict.fromkeys(a)
# {1: None, 2: None}

dict.fromkeys(a, None)
# {1: None, 2: None}

dict.fromkeys(a, 999)
# {1: 999, 2: 999}