傳的是值仍是引用? 構造字典數組的一個bug

在作數據處理的時候, 碰到一個奇怪的現象.數組

for tuple in list.most_common():
    dict['name'] = tuple[0]
    dict['value'] = tuple[1]
    d1.append(dict)   
print(d1)
[{'name': '大興', 'value': 32}, {'name': '大興', 'value': 32}, {'name': '大興', 'value': 32}, {'name': '大興', 'value': 32}, {'name': '大興', 'value': 32}, {'name': '大興', 'value': 32}, {'name': '大興', 'value': 32}]

發現d1這個列表裏的每一個元素都是同樣的. 檢查循環裏的tuple 和 dict 一切正常.
循環裏的d1 就不太正常...app

for tuple in list.most_common():
    dict['name'] = tuple[0]
    dict['value'] = tuple[1]
    d1.append(dict)
    print(d1)
[{'name': '朝陽', 'value': 102}]
[{'name': '海淀', 'value': 65}, {'name': '海淀', 'value': 65}]
[{'name': '昌平', 'value': 53}, {'name': '昌平', 'value': 53}, {'name': '昌平', 'value': 53}]
[{'name': '豐臺', 'value': 53}, {'name': '豐臺', 'value': 53}, {'name': '豐臺', 'value': 53}, {'name': '豐臺', 'value': 53}]
[{'name': '西城', 'value': 48}, {'name': '西城', 'value': 48}, {'name': '西城', 'value': 48}, {'name': '西城', 'value': 48}, {'name': '西城', 'value': 48}]

部分數據是這樣的. 發生了append的操做, 但列表裏全部元素的值都同樣. 爲何會這樣?編碼


幾個小時後, 想到了一種可能性. 在append操做的時候, 傳入的是一個引用, 致使後期dict變化, 前面元素的值也跟着變化. 解決方法是傳入一個dict的copy, 傳一個值, 而不是引用. code

修改後的代碼:開發

for tuple in list.most_common():
    dict['name'] = tuple[0]
    dict['value'] = tuple[1]
    d = copy.copy(dict)
    d1.append(d)
print(d1)
[{'name': '朝陽', 'value': 102}, {'name': '海淀', 'value': 65}, {'name': '豐臺', 'value': 53}, {'name': '昌平', 'value': 53}, {'name': '西城', 'value': 48}, {'name': '通州', 'value': 36}, {'name': '大興', 'value': 32}, {'name': '東城', 'value': 22}, {'name': '順義', 'value': 18}, {'name': '石景山', 'value': 16}, {'name': 'NULL', 'value': 11}, {'name': '房山', 'value': 7}, {'name': '門頭溝', 'value': 6}, {'name': '燕郊', 'value': 5}, {'name': '亦莊開發區', 'value': 3}]

ok, 確實是假想的那樣, 傳引用產生的問題, 加上一個拷貝語句就能夠了. 但是以前也作過很多的利用append來構造字典數組的案例, 從沒碰到過問題, 也沒有添加過拷貝. 仔細觀察之下, 發現個人 dict= {} 聲明是放在for循環外的. 那這應該就是問題所在了.for循環

再次修改後的代碼:循環

for tuple in list.most_common():
    # 把dict的定義放入 for 循環內
    dict = {}
    dict['name'] = tuple[0]
    dict['value'] = tuple[1]
    # d = copy.copy(dict)
    d1.append(dict)
print(d1)

總結一下, 因爲疏忽把dict= {}放在for循環外, 在append的時候, 一直添加的是同一個dict的引用, dict 內的值變化, 引發了列表內全部元素的變化.
在最後的修改裏, 每一次循環, 都會新建一個空字典, 每次循環 dict 都是一個獨立的值. 正確的作法也應該是這樣的. 引用

PS: 嘗試了一下, Js的arr.push(obj) 也有一樣的問題, 固然有良好編碼習慣的人是不會碰到這種問題的.方法

相關文章
相關標籤/搜索