- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有两个 Python 词典,我想编写一个返回这两个词典的单个表达式,合并(即合并)。 update()
方法将是我需要的,如果它返回其结果而不是就地修改字典。
>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}
如何在
z
中获得最终合并的字典,不是
x
?
dict.update()
的最后一个胜利冲突处理也是我正在寻找的。)
最佳答案
How can I merge two Python dictionaries in a single expression?
x
和
y
,
z
成为一个浅合并字典,其值来自
y
替换来自
x
的那些.
z = x | y # NOTE: 3.9+ ONLY
z = {**x, **y}
def merge_two_dicts(x, y):
z = x.copy() # start with keys and values of x
z.update(y) # modifies z with keys and values of y
return z
现在:z = merge_two_dicts(x, y)
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
期望的结果是得到一个新的字典(
z
),其中的值合并,第二个字典的值覆盖第一个字典的值。
>>> z
{'a': 1, 'b': 3, 'c': 4}
一种新的语法,在
PEP 448 中提出和
available as of Python 3.5 , 是
z = {**x, **y}
它确实是一个单一的表达。
z = {**x, 'foo': 1, 'bar': 2, **y}
现在:
>>> z
{'a': 1, 'b': 3, 'foo': 1, 'bar': 2, 'c': 4}
它现在显示为在
release schedule for 3.5, PEP 478 中实现,现在它已进入
What's New in Python 3.5文档。
z = x.copy()
z.update(y) # which returns None since it mutates z
在这两种方法中,
y
将排在第二位,其值将替换
x
的值,因此
b
将指向
3
在我们的最终结果中。
def merge_two_dicts(x, y):
"""Given two dictionaries, merge them into a new dict as a shallow copy."""
z = x.copy()
z.update(y)
return z
然后你有一个表达式:
z = merge_two_dicts(x, y)
您还可以创建一个函数来合并任意数量的字典,从零到一个非常大的数字:
def merge_dicts(*dict_args):
"""
Given any number of dictionaries, shallow copy and merge into a new dict,
precedence goes to key-value pairs in latter dictionaries.
"""
result = {}
for dictionary in dict_args:
result.update(dictionary)
return result
此函数适用于所有字典的 Python 2 和 3。例如给定的词典
a
至
g
:
z = merge_dicts(a, b, c, d, e, f, g)
和
g
中的键值对将优先于字典
a
至
f
, 等等。
z = dict(x.items() + y.items())
在 Python 2 中,您在内存中为每个 dict 创建两个列表,在内存中创建第三个列表,其长度等于前两个列表的长度加在一起,然后丢弃所有三个列表以创建 dict。
在 Python 3 中,这将失败 因为您要添加两个
dict_items
将对象放在一起,而不是两个列表 -
>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'
并且您必须将它们显式创建为列表,例如
z = dict(list(x.items()) + list(y.items()))
.这是一种资源和计算能力的浪费。
items()
的并集在 Python 3(Python 2.7 中的
viewitems()
)中,当值是不可散列的对象(例如列表)时,也会失败。即使您的值是可散列的,
由于集合在语义上是无序的,因此行为在优先级方面是未定义的。所以不要这样做:
>>> c = dict(a.items() | b.items())
这个例子演示了当值不可散列时会发生什么:
>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
这是一个示例,其中
y
应该有优先权,而是来自
x
的值由于集合的任意顺序而保留:
>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}
你不应该使用的另一个黑客:
z = dict(x, **y)
这使用
dict
构造函数并且非常快速和内存高效(甚至比我们的两步过程略多)但是除非您确切地知道这里发生了什么(也就是说,第二个 dict 作为关键字参数传递给 dict 构造函数),它是难以阅读,这不是预期的用法,因此它不是 Pythonic。
frozenset
或元组),但
当键不是字符串时,此方法在 Python 3 中失败。
>>> c = dict(a, **b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
来自
mailing list ,该语言的创造者 Guido van Rossum 写道:
I am fine withdeclaring dict({}, **{1:3}) illegal, since after all it is abuse ofthe ** mechanism.
Apparently dict(x, **y) is going around as "cool hack" for "callx.update(y) and return x". Personally, I find it more despicable thancool.
dict(**y)
的预期用途。用于创建字典以提高可读性,例如:
dict(a=1, b=10, c=11)
代替
{'a': 1, 'b': 10, 'c': 11}
回复评论
Despite what Guido says,
dict(x, **y)
is in line with the dict specification, which btw. works for both Python 2 and 3. The fact that this only works for string keys is a direct consequence of how keyword parameters work and not a short-coming of dict. Nor is using the ** operator in this place an abuse of the mechanism, in fact, ** was designed precisely to pass dictionaries as keywords.
dict
在 Python 2 中打破了这种一致性:
>>> foo(**{('a', 'b'): None})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() keywords must be strings
>>> dict(**{('a', 'b'): None})
{('a', 'b'): None}
考虑到 Python 的其他实现(PyPy、Jython、IronPython),这种不一致是很糟糕的。因此它在 Python 3 中得到了修复,因为这种用法可能是一个突破性的变化。
dict(x.items() + y.items())
is still the most readable solution for Python 2. Readability counts.
merge_two_dicts(x, y)
实际上对我来说似乎更清楚,如果我们真的关心可读性。而且它不向前兼容,因为 Python 2 越来越被弃用。
{**x, **y}
does not seem to handle nested dictionaries. the contents of nested keys are simply overwritten, not merged [...] I ended up being burnt by these answers that do not merge recursively and I was surprised no one mentioned it. In my interpretation of the word "merging" these answers describe "updating one dict with another", and not merging.
from copy import deepcopy
def dict_of_dicts_merge(x, y):
z = {}
overlapping_keys = x.keys() & y.keys()
for key in overlapping_keys:
z[key] = dict_of_dicts_merge(x[key], y[key])
for key in x.keys() - overlapping_keys:
z[key] = deepcopy(x[key])
for key in y.keys() - overlapping_keys:
z[key] = deepcopy(y[key])
return z
用法:
>>> x = {'a':{1:{}}, 'b': {2:{}}}
>>> y = {'b':{10:{}}, 'c': {11:{}}}
>>> dict_of_dicts_merge(x, y)
{'b': {2: {}, 10: {}}, 'a': {1: {}}, 'c': {11: {}}}
提出其他值类型的意外事件远远超出了这个问题的范围,所以我会指向你
my answer to the canonical question on a "Dictionaries of dictionaries merge" .
copy
和
update
或新的解包,因为它们在更高的抽象级别遍历每个键值对,但它们确实尊重优先顺序(后一个字典具有优先级)
{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7
或者在 Python 2.6 中(也许早在 2.4 引入生成器表达式时):
dict((k, v) for d in dicts for k, v in d.items()) # iteritems in Python 2
itertools.chain
将以正确的顺序将迭代器链接到键值对上:
from itertools import chain
z = dict(chain(x.items(), y.items())) # iteritems in Python 2
性能分析
from timeit import repeat
from itertools import chain
x = dict.fromkeys('abcdefg')
y = dict.fromkeys('efghijk')
def merge_two_dicts(x, y):
z = x.copy()
z.update(y)
return z
min(repeat(lambda: {**x, **y}))
min(repeat(lambda: merge_two_dicts(x, y)))
min(repeat(lambda: {k: v for d in (x, y) for k, v in d.items()}))
min(repeat(lambda: dict(chain(x.items(), y.items()))))
min(repeat(lambda: dict(item for d in (x, y) for item in d.items())))
在 Python 3.8.1 中,NixOS:
>>> min(repeat(lambda: {**x, **y}))
1.0804965235292912
>>> min(repeat(lambda: merge_two_dicts(x, y)))
1.636518670246005
>>> min(repeat(lambda: {k: v for d in (x, y) for k, v in d.items()}))
3.1779992282390594
>>> min(repeat(lambda: dict(chain(x.items(), y.items()))))
2.740647904574871
>>> min(repeat(lambda: dict(item for d in (x, y) for item in d.items())))
4.266070580109954
$ uname -a
Linux nixos 4.19.113 #1-NixOS SMP Wed Mar 25 07:06:15 UTC 2020 x86_64 GNU/Linux
词典资源
关于python - 如何在一个表达式中合并两个字典(合并字典)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38987/
我是一名优秀的程序员,十分优秀!