Python 的 dict.fromkeys 的坑
Mar 10, 2023
目前使用到 dict.fromkeys
方法主要有两个场景:一个是按照数组的原有顺序去重,另一个就是正常的根据 keys
构建一个 dict
,这里讨论的是第二种情况。
下面这个例子:
l = ["foo", "bar"]
v = {"age": 0}
d = dict.fromkeys(l, v)
d["foo"]["age"] += 1
d["bar"]["age"] += 1
d["foo"]["age"]
由于 Python 在 v
处存储的是引用而不是值的原因,故 d["foo"]["age"]
最终的值为 2,如果用 id()
方法打印两个对象的地址,可以发现是同一个值。
print(id(d["foo"]["age"]))
print(id(d["bar"]["age"]))
# 140648770627920
# 140648770627920
要解决这个问题,可以适当改一下写法,不使用 fromkeys()
或者避免在 fromkeys
的参数里设置一个引用类型的对象,不然的话属于高危操作了,需要格外注意使用时的场景。
Python 中属于引用类型的对象包括:
- 列表 (list):列表是一种可变序列类型,可以包含任何类型的数据。列表通过 [] 方括号包围,元素之间用逗号分隔。
- 元组 (tuple):元组是一种不可变序列类型,可以包含任何类型的数据。元组通过 () 圆括号包围,元素之间用逗号分隔。
- 集合 (set):集合是一种无序且不重复的集合类型,可以包含任何类型的数据。集合通过 {} 大括号包围,元素之间用逗号分隔。
- 字典 (dict):字典是一种键值对的映射类型,可以包含任何类型的键和值。字典通过 {} 大括号包围,键值对之间用冒号分隔,每个键值对之间用逗号分隔。
- 类 (class):类是一种面向对象的数据类型,可以包含任何属性和方法。
- 函数 (function):函数是一种可调用对象,可以包含任何代码逻辑。函数可以接受参数并返回值。
除了引用类型,Python 还有以下类型:
- 数值型 (Numeric):包括整数 (int)、浮点数 (float)、复数 (complex)。
- 布尔型 (Boolean):包括 True 和 False 两个值,用于表示逻辑真和逻辑假。
- 字符串 (String):字符串是一种不可变序列类型,用于表示文本数据。
- 字节串 (Bytes):字节串是一种不可变序列类型,用于表示二进制数据。
- 字节数组 (Bytearray):字节数组是一种可变序列类型,用于表示二进制数据。
- 空值 (NoneType):None 是一个特殊的值,用于表示空值或缺失值。