234

How do you calculate the union of two dict objects in Python, where a (key, value) pair is present in the result iff key is in either dict (unless there are duplicates)?

For example, the union of {'a' : 0, 'b' : 1} and {'c' : 2} is {'a' : 0, 'b' : 1, 'c' : 2}.

Preferably you can do this without modifying either input dict. Example of where this is useful: Get a dict of all variables currently in scope and their values

6
  • 3
    @RikPoggi: The other question, despite its title, is asking about what the **d2 syntax is. It happens to provide an answer to this question. Commented Mar 23, 2012 at 4:52
  • 8
    merged_dict = {**dict1, **dict2} in python 3.5+ (to save you a trip to the other link or from using the buggy solution accepted here which fails if your keys aren't strings).
    – Nathan
    Commented May 11, 2019 at 1:14
  • merged_dict = dict(**a,**b,**c,**d) worked for me too Commented Jul 23, 2019 at 21:10
  • 2
    Looks like the correct solution will come in Python 3.9, see python.org/dev/peps/pep-0584
    – Attila123
    Commented Apr 23, 2020 at 13:12
  • 3
    Python 3.9 : a = {1: 'a', 2: 'b', 3: 'c'}; b = {4: 'd', 5: 'e'}; c = a | b
    – Pygirl
    Commented Jun 17, 2020 at 6:35

4 Answers 4

173

This question provides an idiom. You use one of the dicts as keyword arguments to the dict() constructor:

dict(y, **x)

Duplicates are resolved in favor of the value in x; for example

dict({'a' : 'y[a]'}, **{'a', 'x[a]'}) == {'a' : 'x[a]'}
15
  • 18
    "Simple is better than complex." :) You should use update member function of dict.
    – shahjapan
    Commented Aug 6, 2012 at 18:51
  • 29
    How is tmp = dict(y); tmp.update(x); do_something(tmp) simpler? Commented Aug 7, 2012 at 6:04
  • 9
    @shahjapan This is not complex, this is great use of Python dict structure. And this is different from update (this solution is not updating anything).
    – lajarre
    Commented Sep 13, 2012 at 9:09
  • 22
    It is not 'nice', it is cryptic, and it immediately makes most readers balk and the remainder assume all the keys in x would have to be legal parameter names. IMHO, the fact it works is a bug in the name-checking mechanisms in the implementation. What happens when you rely on bugs? They either get fixed, or become political footballs in the PEP process. Commented Sep 1, 2014 at 14:54
  • 16
    @JonJayObermark: Agree. dict(x=2) is ok but dict(4=2) is not. So if x={4:2} the proposed method will fail.
    – Miguel
    Commented Apr 9, 2015 at 15:42
127

You can also use update method of dict like

a = {'a' : 0, 'b' : 1}
b = {'c' : 2}

a.update(b)
print a
3
  • 3
    Note that .update changes a. Sometimes, it's inacceptable Commented Mar 18, 2020 at 15:04
  • 4
    do {**d1, **d2}. For details see: stackoverflow.com/questions/38987/… Commented Jul 13, 2020 at 21:17
  • why does this fail? ` self.indices_to_labels = dict(**self.labels_to_indices, **global_label2global_indices) ` Commented Oct 27, 2022 at 17:26
72

For a static dictionary, combining snapshots of other dicts:

As of Python 3.9, the binary "or" operator | has been defined to concatenate dictionaries. (A new, concrete dictionary is eagerly created):

>>> a = {"a":1}
>>> b = {"b":2}
>>> a|b
{'a': 1, 'b': 2}

Conversely, the |= augmented assignment has been implemented to mean the same as calling the update method:

>>> a = {"a":1}
>>> a |= {"b": 2}
>>> a
{'a': 1, 'b': 2}

For details, check PEP-584

Prior to Python 3.9, the simpler way to create a new dictionary is to create a new dictionary using the "star expansion" to add teh contents of each subctionary in place:

c = {**a, **b}

For dynamic dictionary combination, working as "view" to combined, live dicts:

If you need both dicts to remain independent, and updatable, you can create a single object that queries both dictionaries in its __getitem__ method (and implement get, __contains__ and other mapping method as you need them).

A minimalist example could be like this:

class UDict(object):
   def __init__(self, d1, d2):
       self.d1, self.d2 = d1, d2
   def __getitem__(self, item):
       if item in self.d1:
           return self.d1[item]
       return self.d2[item]

And it works:

>>> a = UDict({1:1}, {2:2})
>>> a[2]
2
>>> a[1]
1
>>> a[3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 7, in __getitem__
KeyError: 3
>>> 

NB: If one wants to lazily maintain a Union "view" of two or more dictionaries, check collections.ChainMap in the standard library - as it has all dictionary methods and cover corner cases not contemplated in the example above.

3
  • 1
    do {**d1, **d2}. For details see: stackoverflow.com/questions/38987/… Commented Jul 13, 2020 at 21:18
  • sorry @neuron - your edit broke the answer. The second part is not only to older versions, it describes how to create a custom mapping which can reference independent sub-dictionaries, and this has nothing to do with the language version. (I should come back in a few minutes and fix it back, but please, watch out for the meaning of the text/code when editing)
    – jsbueno
    Commented Sep 21, 2021 at 13:37
  • why does this fail? ` self.indices_to_labels = dict(**self.labels_to_indices, **global_label2global_indices) ` Commented Oct 27, 2022 at 17:26
39

Two dictionaries

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n dictionaries

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))
5
  • 19
    Or much more readably, dict(i for dct in dicts for i in dct.items())
    – Eric
    Commented May 13, 2013 at 9:12
  • Why converting to list() ? def union2(dict1, dict2): return dict(dict1.items() + dict2.items()) Commented May 22, 2017 at 14:48
  • 2
    @kinORnirvana In python 3: a = {'x': 1}; type(a.items()) => <class 'dict_items'> Commented May 23, 2017 at 13:55
  • @kinORnirvana "Why converting to list() ?" Because otherwise: "TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'".
    – Attila123
    Commented Apr 23, 2020 at 13:14
  • 1
    do {**d1, **d2}. For details see: stackoverflow.com/questions/38987/… Commented Jul 13, 2020 at 21:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.