for内で配列に辞書を追加しても参照型なので更新されない
配列に辞書を追加しようと下のように書いた場合、追加したすべての辞書の要素が同じ値になる。
dictの場合
list = []
dict = {}
for num in range(10):
dict['num'] = num
list.append(dict)
print(list)
# 実行結果
# [{'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}, {'num': 9}]
ちなみに配列でも同じようになる。
listの場合
list_1 = [0]
list_2 = []
for num in range(10):
list_1[0] = num
list_2.append(list_1)
print(list_2)
# 実行結果
# [[9], [9], [9], [9], [9], [9], [9], [9], [9], [9]]
辞書と配列の要素書き換えの場合は参照渡しになる
変数の書き換え時は参照渡しにならない。
下のようにメモリアドレスが別になっている。
num = 1
print(id(num))
# 実行結果
# 1749329840
num = 2
print(id(num))
# 実行結果
# 1749329856
辞書もしくは配列の書き換えの場合は参照渡しになる。
辞書の場合
dict = {}
print(id(dict))
# 実行結果
# 30770832
dict['num'] = 1
print(id(dict))
# 実行結果
# 30770832
# 初期化するとアドレスが変わる
dict = {}
print(id(dict))
# 実行結果
# 30770712
配列の場合
list = []
print(id(list))
# 実行結果
# 31884968
list.append(1)
print(id(list))
# 実行結果
# 31884968
# 初期化するとアドレスが変わる
list = []
print(id(list))
# 実行結果
# 31948872
対策
方法1
for内で初期化する
list = []
for num in range(10):
dict = {}
dict['num'] = num
list.append(dict)
print(list)
# 実行結果
# [{'num': 0}, {'num': 1}, {'num': 2}, {'num': 3}, {'num': 4}, {'num': 5}, {'num': 6}, {'num': 7}, {'num': 8}, {'num': 9}]
方法2
copyメソッドを使用する
list = []
for num in range(10):
dict = {}
dict['num'] = num
list.append(dict.copy())
print(list)
# 実行結果
# [{'num': 0}, {'num': 1}, {'num': 2}, {'num': 3}, {'num': 4}, {'num': 5}, {'num': 6}, {'num': 7}, {'num': 8}, {'num': 9}]
copyメソッドは配列でも使用可能
方法3
辞書にした状態で代入する
list = []
for num in range(10):
dict = {'num': num}
list.append(dict)
print(list)
# 実行結果
# [{'num': 0}, {'num': 1}, {'num': 2}, {'num': 3}, {'num': 4}, {'num': 5}, {'num': 6}, {'num': 7}, {'num': 8}, {'num': 9}]
まとめ
pythonにおいて、辞書・配列の変数の代入は参照渡しになると覚えておけばいい。
また、copy等を使いすぎるとメモリが足らなくなるので必要な時だけ使用する。