Python中dict的值为list的问题

本质上,如果你设置一个dict的值为list,那么你大概率是想该dict的键能够映射多个值,并且能够不断的增添、删除或者修改。
Python中list的操作总是简单的,所以很多时候我都将容器设置为list,而在这次操作中,却踩了坑。

dict的值为list的坑

1
2
3
4
5
6
info_keys = ['NAME', 'AGE', 'SEX']
info_all = dict.fromkeys(info_keys, [])
info = {'NAME': 'Tom', 'AGE': 22, 'SEX': 'F'}
for key in info_keys:
info_all[key].append(info[key])
print(info_all)

输出却为:

1
{'NAME': ['Tom', 22, 'F'], 'AGE': ['Tom', 22, 'F'], 'SEX': ['Tom', 22, 'F']}

为什么?
事实上,使用fromkeys()后,所有键都指向同一个值,可使用id()函数查看字典三个键的内存地址均相同:

1
2
>>> print(id(info_all['NAME']), id(info_all['AGE']), id(info_all['SEX']))
4507619272 4507619272 4507619272

正确方法

1
2
3
4
5
6
info_keys = ['NAME', 'AGE', 'SEX']
info_all = {'NAME': [], 'AGE': [], 'SEX': []}
info = {'NAME': 'Tom', 'AGE': 22, 'SEX': 'F'}
for key in info_keys:
info_all[key].append(info[key])
print(info_all)

此时:

1
2
>>> print(id(info_all['NAME']), id(info_all['AGE']), id(info_all['SEX']))
4419928008 4420628360 4420627528

或者

1
2
3
4
5
6
info_keys = ['NAME', 'AGE', 'SEX']
info_all = {}
info = {'NAME': 'Tom', 'AGE': 22, 'SEX': 'F'}
for key in info_keys:
info_all.setdefault(key, []).append(info[key])
print(info_all)

均能正确输出结果:

1
{'NAME': ['Tom'], 'AGE': [22], 'SEX': ['F']}

此时:

1
2
>>> print(id(info_all['NAME']), id(info_all['AGE']), id(info_all['SEX']))
4317806536 4318506888 4318506056

参考

https://python3-cookbook.readthedocs.io/zh_CN/latest/c01/p06_map_keys_to_multiple_values_in_dict.html