108
d3 = dict(d1, **d2)

I understand that this merges the dictionary. But, is it unique? What if d1 has the same key as d2 but different value? I would like d1 and d2 to be merged, but d1 has priority if there is duplicate key.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
TIMEX
  • 259,804
  • 351
  • 777
  • 1,080
  • 10
    Please be aware that this trick is considered an abuse of `**` keyword argument passing unless all keys of `d2` are strings. If not all keys of `d2` are strings, this fails in Python 3.2, and in alternative implementations of Python like Jython, IronPython and PyPy. See, for example, http://mail.python.org/pipermail/python-dev/2010-April/099459.html . – Mark Dickinson May 10 '10 at 09:23
  • 3
    possible duplicate of [How can I merge two Python dictionaries in a single expression?](http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single-expression) – Alastair Irvine Jun 25 '15 at 15:14

7 Answers7

172

You can use the .update() method if you don't need the original d2 any more:

Update the dictionary with the key/value pairs from other, overwriting existing keys. Return None.

E.g.:

>>> d1 = {'a': 1, 'b': 2} 
>>> d2 = {'b': 1, 'c': 3}
>>> d2.update(d1)
>>> d2
{'a': 1, 'c': 3, 'b': 2}

Update:

Of course you can copy the dictionary first in order to create a new merged one. This might or might not be necessary. In case you have compound objects (objects that contain other objects, like lists or class instances) in your dictionary, copy.deepcopy should also be considered.

Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 2
    With this case d1 elements should correctly get priority if conflicting keys are found – Trey Hunner May 09 '10 at 20:36
  • 1
    In case you still need it, just make a copy. d3 = d2.copy() d3.update(d1) but I would like to see d1 + d2 being added to the language. – stach May 09 '10 at 20:37
  • 5
    d1 + d2 is problematic because one dictionary has to have priority during conflicts, and it's not particularly obvious which one. – rjh May 09 '10 at 20:39
  • 1
    d1 + d2 will only ever be implemented if Python gains a multimap, otherwise the ambiguity to the user is too confusing for the 8 byte typing gain. – Nick Bastin May 09 '10 at 20:54
  • 1
    You have objects in the dictionary in this example: `isinstance(int, object) is True` yet `deepcopy` doesn't seem necessary. – Antony Hatchkins Jun 12 '13 at 05:55
  • 1
    +1 for `copy.deepcopy`. @AntonyHatchkins `int` and `str`, while technically `objects`, generally have true copies made, but other objects (`list`, `dict`, any user-defined classes, etc) will only have shallow copies made unless `deepcopy` is called. Up to the user and the scenario which is preferred (shallow-vs-deep). – dwanderson Feb 16 '17 at 21:57
  • @dwanderson Yes, I'm aware of that. But "In case you have objects in your dictionary, `copy.deepcopy` should also be considered." part is incorrect and should be reworded. – Antony Hatchkins Feb 17 '17 at 03:57
  • @AntonyHatchkins there's nothing incorrect about *considering* `deepcopy`, depending on your needs. It's totally valid and appropriate to mention here. Maybe you want it to say "in case you have more complex objects [...]"? – dwanderson Feb 18 '17 at 16:03
  • @dwanderson yes, this second part is correct. First part needs rewording. – Antony Hatchkins Feb 18 '17 at 16:46
  • @dwanderson I've made the necessary fix. – Antony Hatchkins Feb 19 '17 at 16:23
46

In Python2,

d1={'a':1,'b':2}
d2={'a':10,'c':3}

d1 overrides d2:

dict(d2,**d1)
# {'a': 1, 'c': 3, 'b': 2}

d2 overrides d1:

dict(d1,**d2)
# {'a': 10, 'c': 3, 'b': 2}

This behavior is not just a fluke of implementation; it is guaranteed in the documentation:

If a key is specified both in the positional argument and as a keyword argument, the value associated with the keyword is retained in the dictionary.

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 3
    Your examples will fail (producing a TypeError) in Python 3.2, and in current versions of Jython, PyPy and IronPython: for those versions of Python, when passing a dict with the `**` notation, all the keys of that dict should be strings. See the python-dev thread starting at http://mail.python.org/pipermail/python-dev/2010-April/099427.html for more. – Mark Dickinson May 10 '10 at 09:27
  • @Mark: Thanks for the heads up. I've edited the code to make it compatible with non-CPython implementations. – unutbu May 10 '10 at 17:50
  • 3
    it fails if your keys are tuples of strings and numbers. for eg. d1={(1,'a'):1, (1,'b'):0,} d2={(1,'a'):1, (2,'b'):2, (2,'a'):1,} – MySchizoBuddy Jul 29 '13 at 06:41
  • Regarding the unpacking syntax, see [this post](http://stackoverflow.com/a/26853961/1959808) for changes forthcoming in python 3.5. – 0 _ Apr 11 '15 at 04:07
  • I was going to say that `d = dict(**d1, **d2)` works, but that's what @IoannisFilippidis references in their comment. Perhaps including the snippet here would've been clearer, so here it is. – dwanderson Feb 16 '17 at 21:51
  • asterisks explained - https://stackoverflow.com/questions/36901/what-does-double-star-asterisk-and-star-asterisk-do-for-parameters – cardamom Jan 17 '19 at 12:47
21

Starting in Python 3.9, the operator | creates a new dictionary with the merged keys and values from two dictionaries:

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d3 = d2 | d1
# d3: {'b': 2, 'c': 3, 'a': 1}

This:

Creates a new dictionary d3 with the merged keys and values of d2 and d1. The values of d1 take priority when d2 and d1 share keys.


Also note the |= operator which modifies d2 by merging d1 in, with priority on d1 values:

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d2 |= d1
# d2: {'b': 2, 'c': 3, 'a': 1}

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
  • 1
    Thanks for the answer, didn't know that works yet, but it is a very convenient way of merging two dicts, definitely an easy one to remember for me ^^ – zomilanovic Aug 14 '23 at 08:27
15

If you want d1 to have priority in the conflicts, do:

d3 = d2.copy()
d3.update(d1)

Otherwise, reverse d2 and d1.

tzot
  • 92,761
  • 29
  • 141
  • 204
3

My solution is to define a merge function. It's not sophisticated and just cost one line. Here's the code in Python 3.

from functools import reduce
from operator import or_

def merge(*dicts):
    return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }

Tests

>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d, d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d_letters, d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> merge(d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge()
{}

It works for arbitrary number of dictionary arguments. Were there any duplicate keys in those dictionary, the key from the rightmost dictionary in the argument list wins.

Lei Zhao
  • 986
  • 10
  • 11
  • 1
    A simple loop with an `.update` call in it (`merged={}` followed by `for d in dict: merged.update(d)`) would be shorter, more readable and more efficient. – Mark Dickinson Feb 07 '15 at 09:03
  • 1
    Or if you really want to use `reduce` and `lambda`s, how about `return reduce(lambda x, y: x.update(y) or x, dicts, {})`? – Mark Dickinson Feb 07 '15 at 09:07
  • 1
    You can try out your code in the shell and see if it's correct. What I was trying to do is to write a function that can take various number of dictionary arguments with the same functionality. It's better not to use x.update(y) under the lambda, because it always returns _None_. And I am trying to write a more general function _merge\_with_ that take various number of dictionary argument and deal with duplicate keys with the supplied function. Once I am done, I'll post it in another thread where the solution is more relevant. – Lei Zhao Feb 07 '15 at 09:34
  • Here's [link](http://stackoverflow.com/questions/16560840/python-merge-dictionaries-with-custom-merge-function/28381494#28381494) where I wrote the more general solution. Welcome and have a look. – Lei Zhao Feb 07 '15 at 11:54
3

Trey Hunner has a nice blog post outlining several options for merging multiple dictionaries, including (for python3.3+) ChainMap and dictionary unpacking.

pfctdayelise
  • 5,115
  • 3
  • 32
  • 52
2

I believe that, as stated above, using d2.update(d1) is the best approach and that you can also copy d2 first if you still need it.

Although, I want to point out that dict(d1, **d2) is actually a bad way to merge dictionnaries in general since keyword arguments need to be strings, thus it will fail if you have a dict such as:

{1: 'foo', 2: 'bar'}
Olivier Melançon
  • 21,584
  • 4
  • 41
  • 73