python - 为什么dict不支持算术?
问题描述
在 Python 中,可以对列表和元组求和,例如
>>> print([1, 2] + [4, 5])
>>> [1, 2, 4, 5]
>>> print((1, 2) + (4, 5))
>>> (1, 2, 3, 4)
但是尝试对 dicts 做同样的事情会引发:
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
update()
我想在合并两个具有相同键的字典时可能会有相同的行为:
>>> foo = {'a': 10, 'b': 20}
>>> bar = {'a': 20}
>>> foo.update(bar)
>>> print(foo)
>>> {'a': 20, 'b': 20}
为什么这些操作数没有实现?有任何优化问题还是设计问题?
解决方案
2020 年 5 月更新: 本答案中讨论的PEP 584已于 2020 年 2 月被接受,并将成为 Python 3.9 中的一项功能。我认为下面的讨论是我最初答案的一部分,今天仍然具有相关性,我暂时将其保留为上下文。
原答案:
这已被考虑(见PEP 584)。但是,也存在一些问题。那里考虑了一些非常有趣的观点,绝对值得一读。主要是:如果发生冲突(即我们要添加的字典中重复相同的键)会发生什么?此外,具有不可交换的加法运算也不是很好,并且重复的加法不等于乘法。
有关反对的详细列表,请参阅PEP 584:主要反对。
让我们简单地回顾一下(下面的讨论可以看作是对 PEP 584 的总结,我仍然建议你去阅读它):
字典加法不可交换
这源于这样一个事实,即如果我们试图加起来的两个字典中存在键,那么最好的解决方案可能是选择“获胜方”。我的意思是,如果可以添加 dict,那么下面的代码应该做什么:
dictA = {"key1": 1, "key2": 2}
dictB = {"key1": 3, "key2": 4}
dictC = dictA + dictB
print(dictC) # ???
dictA + dictB
具有与 相似的结果是有意义的dictA.update(dictB)
,其中dictB
将“覆盖”两个字典中重复的键的值。然而,这导致了问题:
我们希望加法运算是可交换的,但dictA + dictB
不同于dictB + dictA
.
一个反驳的论点是已经存在不可交换的加法运算,例如列表或字符串加法:
listA = [1, 2]
listB = [3, 4]
print(listA + listB) # [1, 2, 3, 4]
print(listB + listA) # [3, 4, 1, 2]
话虽如此,我敢打赌大多数人并不介意,因为很自然地认为listA + listB
是列表连接,当给定一个表达式时,我们直观地知道会发生什么(字符串添加/连接也是如此)。自然而然地,它listB + listA
会返回一些不同的东西。但是,推断会产生什么并不明显dictA + dictB
(这是主观的,但我认为大多数人都会同意这一点)。
请注意,还有其他可能的解决冲突的方法,但它们都有自己的问题。
字典添加将是低效的
考虑将许多字典添加在一起:
dictA + dictB + dictC + dictD ...
字典添加不能很好地扩展,并且允许这样的表达可能会鼓励不良做法。这又是主观的(就像所有这些反对意见一样),但这似乎是一个普遍的问题。
重复加法应该等价于乘法
我之前提到过这个。如果允许加法,人们会期望有一个表示重复加法的乘法运算符,类似于列表和字符串可能的情况:
listA = [1, 2]
stringA = 'abc'
dictA = {"key1": 1, "key2": 2}
print( listA*3 ) # [1, 2, 1, 2, 1, 2] -- similar to listA + listA + listA
print( stringA*3) # abcabcabc -- similar to stringA + stringA + stringA
print( dictA*3) # ???
我们将如何以自然的方式处理这个问题?
字典加法是有损的
如果我们以同样的方式处理冲突dictA.update(dictB)
,那么这将导致一个丢失数据的加法操作,而没有其他形式的加法是有损的。
Dict contains tests will fail
我们希望a in a+b
这是真的,这也适用于其他类型,例如字符串和元组:
print(stringA in stringA + stringB) # True
这是有争议的,因为这不适用于其他系列。
只有一种方法 - 不止一种方法
高度主观且值得商榷,但许多人认为,没有一种“自然”的方式来处理冲突这一事实违反了 Python 之禅中的一项原则:
应该有一种——最好只有一种——明显的方法来做到这一点。
字典加法不像连接
同样,源自字典中添加的另一个反对意见与其他集合(例如列表)中的添加不同。有些人认为这是有问题的:
len(dictA + dictB) == len(dictA) + len(dictB) # False
字典添加使代码更难理解
最后,PEP 584 中列出的最后一个反对意见是我们一次又一次地讨论过的,dictA + dictB
不直观,而且很难知道那段代码会做什么。
推荐阅读
- angular - “typeof import”类型不存在属性“realtime”
- svelte - 如何在 Svelte 中删除 PostCSS 生成的空样式?
- python - 在 RPi 上安装 matplotlib 时出现枕头错误
- google-chrome - 我如何修改字体以在多个设备中获得相同的结果
- typescript - 在客户端 Typescript 文件中导入 socket.io 时未捕获 TypeError
- r - 创建具有均值和置信区间的 ggplot
- javascript - 在 ThreeJS 中使用新的 PlaneBufferGeometry 访问顶点
- python - 贪心算法将数字列表列表分成两个分区,Python中每个数字的数量相同
- apache-spark - Petastorm:parquet 文件中的非原始数据类型
- r - 在R中,提取一定长度或更长的所有子字符串