我想将两个词典融入一个新的词典。

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
z = merge(x, y)

>>> z
{'a': 1, 'b': 3, 'c': 4}

每当两个字典中都有一个关键 k 时,只应保留 y(k) 的值。


当前回答

如果你不想转动X,

x.update(y) or x

(x.update(y), x)[-1]

如果你还没有X在变量,你可以使用Lambda做一个地方,而不使用任务声明,这意味着使用Lambda作为一个Let表达,这是一个常见的技术在功能语言,但可能是无神论的。

(lambda x: x.update(y) or x)({'a': 1, 'b': 2})

(x := {'a': 1, 'b': 2}).update(y) or x

(lambda x={'a': 1, 'b': 2}: x.update(y) or x)()

如果你想要一个副本,PEP 584 风格 x <unk> y 是最 Pythonic 的 3.9+. 如果你需要支持更古老的版本,PEP 448 风格 {**x, **y} 是最容易的 3.5+. 但如果它不在你的(甚至更古老的) Python 版本,让表达模式也在这里工作。

(lambda z=x.copy(): z.update(y) or z)()

(当然,这可能相当于(z := x.copy())。更新(y)或z,但如果您的Python版本足够新,那么PEP 448风格将可用。

其他回答

在 Python 3.0 或更高版本中,您可以使用.ChainMap 集合多个字符或其他地图,以创建一个单一的可更新视图:

>>> from collections import ChainMap
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = dict(ChainMap({}, y, x))
>>> for k, v in z.items():
        print(k, '-->', v)
    
a --> 1
b --> 10
c --> 11

更新 Python 3.5 或更高版本: 您可以使用 PEP 448 延伸字典包装和解包。

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> {**x, **y}
{'a': 1, 'b': 10, 'c': 11}

更新 Python 3.9 或更高版本: 您可以使用 PEP 584 联盟运营商:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x | y
{'a': 1, 'b': 10, 'c': 11}
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

对于两个字典中的关键物品(“b”),您可以通过将最后一个放在输出中来控制哪个。

在Python3中,项目方法不再返回一个列表,而是一个视图,它像一个集一样作用。

dict(x.items() | y.items())

dict(x.viewitems() | y.viewitems())

编辑:

首先,请注意,在 Python 3 中, dic(x、 **y) 技巧不会工作,除非 y 中的键是线条。

此外,Raymond Hettinger的链路图答案是相当优雅的,因为它可以作为论点采取任意数量的论点,但从论点看起来它顺序地通过每个搜索的所有论点的列表:

In [1]: from collections import ChainMap
In [2]: from string import ascii_uppercase as up, ascii_lowercase as lo; x = dict(zip(lo, up)); y = dict(zip(up, lo))
In [3]: chainmap_dict = ChainMap(y, x)
In [4]: union_dict = dict(x.items() | y.items())
In [5]: timeit for k in union_dict: union_dict[k]
100000 loops, best of 3: 2.15 µs per loop
In [6]: timeit for k in chainmap_dict: chainmap_dict[k]
10000 loops, best of 3: 27.1 µs per loop

我是 Chainmap 的粉丝,但看起来不太实用,在那里可能有很多搜索。

深深的定律:

from typing import List, Dict
from copy import deepcopy

def merge_dicts(*from_dicts: List[Dict], no_copy: bool=False) -> Dict :
    """ no recursion deep merge of two dicts

    By default creates fresh Dict and merges all to it.

    no_copy = True, will merge all dicts to a fist one in a list without copy.
    Why? Sometime I need to combine one dictionary from "layers".
    The "layers" are not in use and dropped immediately after merging.
    """

    if no_copy:
        xerox = lambda x:x
    else:
        xerox = deepcopy

    result = xerox(from_dicts[0])

    for _from in from_dicts[1:]:
        merge_queue = [(result, _from)]
        for _to, _from in merge_queue:
            for k, v in _from.items():
                if k in _to and isinstance(_to[k], dict) and isinstance(v, dict):
                    # key collision add both are dicts.
                    # add to merging queue
                    merge_queue.append((_to[k], v))
                    continue
                _to[k] = xerox(v)

    return result

使用:

print("=============================")
print("merge all dicts to first one without copy.")
a0 = {"a":{"b":1}}
a1 = {"a":{"c":{"d":4}}}
a2 = {"a":{"c":{"f":5}, "d": 6}}
print(f"a0 id[{id(a0)}] value:{a0}")
print(f"a1 id[{id(a1)}] value:{a1}")
print(f"a2 id[{id(a2)}] value:{a2}")
r = merge_dicts(a0, a1, a2, no_copy=True)
print(f"r  id[{id(r)}] value:{r}")

print("=============================")
print("create fresh copy of all")
a0 = {"a":{"b":1}}
a1 = {"a":{"c":{"d":4}}}
a2 = {"a":{"c":{"f":5}, "d": 6}}
print(f"a0 id[{id(a0)}] value:{a0}")
print(f"a1 id[{id(a1)}] value:{a1}")
print(f"a2 id[{id(a2)}] value:{a2}")
r = merge_dicts(a0, a1, a2)
print(f"r  id[{id(r)}] value:{r}")

最好的版本我可以想象,而不使用复制将是:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))

它比 dict(x.items() + y.items()) 更快,但不像 n = copy(a); n.update(b),至少在 CPython 上。

我个人最喜欢这个版本,因为它在一个单一的功能合成中描述了我想要的东西相当好,唯一的小问题是,它并不完全显而易见,Y的值超过X的值,但我不认为很难找到它。