python for内で配列に辞書を追加したら参照型になって更新されない

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等を使いすぎるとメモリが足らなくなるので必要な時だけ使用する。

この記事のタグ
Share
© 2020 heisen-tech.com Inc.