How do I merge two dictionaries in a single expression (taking union of dictionaries)?

Created 02.09.2008 07:44
Viewed 2.26M times
5615 votes

I have two Python dictionaries, and I want to write a single expression that returns these two dictionaries, merged (i.e. taking the union). The update() method would be what I need, if it returned its result instead of modifying a dictionary in-place.

>>> x = {'a': 1, 'b': 2}
>>> y = {'b': 10, 'c': 11}
>>> z = x.update(y)
>>> print(z)
None
>>> x
{'a': 1, 'b': 10, 'c': 11}

How can I get that final merged dictionary in z, not x?

(To be extra-clear, the last-one-wins conflict-handling of dict.update() is what I'm looking for as well.)

0
Answers 49
21
7061

How can I merge two Python dictionaries in a single expression?

For dictionaries x and y, z becomes a shallowly merged dictionary with values from y replacing those from x.

  • In Python 3.9.0 or greater (released 17 October 2020): PEP-584, discussed here, was implemented and provides the simplest method:

    z = x | y          # NOTE: 3.9+ ONLY
    
  • In Python 3.5 or greater:

    z = {**x, **y}
    
  • In Python 2, (or 3.4 or lower) write a function:

    def merge_two_dicts(x, y):
        z = x.copy()   # start with x's keys and values
        z.update(y)    # modifies z with y's keys and values & returns None
        return z
    

    and now:

    z = merge_two_dicts(x, y)
    

Explanation

Say you have two dictionaries and you want to merge them into a new dict without altering the original dictionaries:

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

The desired result is to get a new dictionary (z) with the values merged, and the second dictionary's values overwriting those from the first.

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

A new syntax for this, proposed in PEP 448 and available as of Python 3.5, is

z = {**x, **y}

And it is indeed a single expression.

Note that we can merge in with literal notation as well:

z = {**x, 'foo': 1, 'bar': 2, **y}

and now:

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

It is now showing as implemented in the release schedule for 3.5, PEP 478, and it has now made its way into What's New in Python 3.5 document.

However, since many organizations are still on Python 2, you may wish to do this in a backward-compatible way. The classically Pythonic way, available in Python 2 and Python 3.0-3.4, is to do this as a two-step process:

z = x.copy()
z.update(y) # which returns None since it mutates z

In both approaches, y will come second and its values will replace x's values, thus 'b' will point to 3 in our final result.

Not yet on Python 3.5, but want a single expression

If you are not yet on Python 3.5 or need to write backward-compatible code, and you want this in a single expression, the most performant while the correct approach is to put it in a function:

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

and then you have a single expression:

z = merge_two_dicts(x, y)

You can also make a function to merge an undefined number of dictionaries, from zero to a very large number:

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

This function will work in Python 2 and 3 for all dictionaries. e.g. given dictionaries a to g:

z = merge_dicts(a, b, c, d, e, f, g) 

and key-value pairs in g will take precedence over dictionaries a to f, and so on.

Critiques of Other Answers

Don't use what you see in the formerly accepted answer:

z = dict(x.items() + y.items())

In Python 2, you create two lists in memory for each dict, create a third list in memory with length equal to the length of the first two put together, and then discard all three lists to create the dict. In Python 3, this will fail because you're adding two dict_items objects together, not two lists -

>>> 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'

and you would have to explicitly create them as lists, e.g. z = dict(list(x.items()) + list(y.items())). This is a waste of resources and computation power.

Similarly, taking the union of items() in Python 3 (viewitems() in Python 2.7) will also fail when values are unhashable objects (like lists, for example). Even if your values are hashable, since sets are semantically unordered, the behavior is undefined in regards to precedence. So don't do this:

>>> c = dict(a.items() | b.items())

This example demonstrates what happens when values are unhashable:

>>> x = {'a': []}
>>> y = {'b': []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Here's an example where y should have precedence, but instead the value from x is retained due to the arbitrary order of sets:

>>> x = {'a': 2}
>>> y = {'a': 1}
>>> dict(x.items() | y.items())
{'a': 2}

Another hack you should not use:

z = dict(x, **y)

This uses the dict constructor and is very fast and memory-efficient (even slightly more-so than our two-step process) but unless you know precisely what is happening here (that is, the second dict is being passed as keyword arguments to the dict constructor), it's difficult to read, it's not the intended usage, and so it is not Pythonic.

Here's an example of the usage being remediated in django.

Dictionaries are intended to take hashable keys (e.g. frozensets or tuples), but this method fails in Python 3 when keys are not strings.

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

From the mailing list, Guido van Rossum, the creator of the language, wrote:

I am fine with declaring dict({}, **{1:3}) illegal, since after all it is abuse of the ** mechanism.

and

Apparently dict(x, **y) is going around as "cool hack" for "call x.update(y) and return x". Personally, I find it more despicable than cool.

It is my understanding (as well as the understanding of the creator of the language) that the intended usage for dict(**y) is for creating dictionaries for readability purposes, e.g.:

dict(a=1, b=10, c=11)

instead of

{'a': 1, 'b': 10, 'c': 11}

Response to comments

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.

Again, it doesn't work for 3 when keys are non-strings. The implicit calling contract is that namespaces take ordinary dictionaries, while users must only pass keyword arguments that are strings. All other callables enforced it. dict broke this consistency in 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}

This inconsistency was bad given other implementations of Python (Pypy, Jython, IronPython). Thus it was fixed in Python 3, as this usage could be a breaking change.

I submit to you that it is malicious incompetence to intentionally write code that only works in one version of a language or that only works given certain arbitrary constraints.

More comments:

dict(x.items() + y.items()) is still the most readable solution for Python 2. Readability counts.

My response: merge_two_dicts(x, y) actually seems much clearer to me, if we're actually concerned about readability. And it is not forward compatible, as Python 2 is increasingly deprecated.

{**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.

Yes. I must refer you back to the question, which is asking for a shallow merge of two dictionaries, with the first's values being overwritten by the second's - in a single expression.

Assuming two dictionaries of dictionaries, one might recursively merge them in a single function, but you should be careful not to modify the dictionaries from either source, and the surest way to avoid that is to make a copy when assigning values. As keys must be hashable and are usually therefore immutable, it is pointless to copy them:

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

Usage:

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

Coming up with contingencies for other value types is far beyond the scope of this question, so I will point you at my answer to the canonical question on a "Dictionaries of dictionaries merge".

Less Performant But Correct Ad-hocs

These approaches are less performant, but they will provide correct behavior. They will be much less performant than copy and update or the new unpacking because they iterate through each key-value pair at a higher level of abstraction, but they do respect the order of precedence (latter dictionaries have precedence)

You can also chain the dictionaries manually inside a dict comprehension:

{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7

or in python 2.6 (and perhaps as early as 2.4 when generator expressions were introduced):

dict((k, v) for d in dicts for k, v in d.items()) # iteritems in Python 2

itertools.chain will chain the iterators over the key-value pairs in the correct order:

from itertools import chain
z = dict(chain(x.items(), y.items())) # iteritems in Python 2

Performance Analysis

I'm only going to do the performance analysis of the usages known to behave correctly. (Self-contained so you can copy and paste yourself.)

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())))

In 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

Resources on Dictionaries

10.11.2014 22:11
Comments
Strings only limitation for keywords expansion is enough to rule out {**x, **y} method. However, the items approach can be made workable by converting dictitems to list like dict(list(x.items()), list(y.items())). by Mohammad Azim, 16.05.2019 15:00
@MohammadAzim "strings only" only applies to keyword argument expansion in callables, not generalized unpacking syntax. To demonstrate that this works: {**{(0, 1):2}} -> {(0, 1): 2} by Aaron Hall, 16.05.2019 16:07
If dict1 and dict2 have some keys in common, {**dict1, **dict2} raises TypeError: type object got multiple values for keyword argument common_key_name. I guess I'll stay with {dict1, **dict2} and string keys. by Richard_wth, 22.08.2019 06:04
@Richard_wth - that error message is unrelated. Check out this answer: stackoverflow.com/questions/18950054/… by Aaron Hall, 22.08.2019 12:30
This may be changed when PEP-0584 is accepted. A new union operator will be implemented with the following syntax: x | y by Callam Delaney, 28.02.2020 16:26
@cal97g yes, I addressed that in my answer about 10 days ago: stackoverflow.com/posts/26853961/revisions by Aaron Hall, 28.02.2020 16:38
Ah yes, the union operator! If it works for sets, why shouldn't it work for dicts? Really looking forward to PEP 584. by Arthur Khazbs, 05.03.2020 00:08
@GringoSuave Are you saying that it needs a summary? Because I would characterize the first part as a summary. If you say it's too long, what would you like to cut from this answer, that you think, in the cutting, would create value for users? Cheers! by Aaron Hall, 11.03.2020 17:32
Hi, the top is a summary, yes. Up to you. The whole thing would be a great blog post. Note Py 3.4 and below are EOL, 3.5 approaching EOL in 2020-09. by Gringo Suave, 13.03.2020 02:09
I agree with Gringo, this answer should be made shorter by removing all mention of Python < 3.5. by Neil G, 17.05.2020 14:33
I agree with the eagerness to leave the old way behind, but sometimes people have to work in environments where they only have the older technology available to them. People also have to update code, and seeing the old way next to the new way allows them to confidently replace the old code with equivalent new code. I am open to suggestions on reorganizing the material, but I think we need to keep the older information. by Aaron Hall, 17.05.2020 15:04
Here's the expected release schedule: python.org/dev/peps/pep-0596 by Aaron Hall, 31.07.2020 01:53
What x and y did you use in the benchmarks? And I find dict((k, v) ... for k, v in d.items()) somewhat clumsy and artificially inefficient. No need to unpack and repack every item. I think it should be dict(item ... for item in d.items()). by superb rain, 28.08.2020 22:56
@superbrain x and y I don't recall right now. that's a fair point about item. I'll review it. by Aaron Hall, 28.08.2020 23:23
@AaronHall With fresh new benchmarks, thanks :-). You have another dict((k, v) ...) a bit higher in your post, btw. And I just thought of another solution that I think hasn't been mentioned yet: dict([*x.items(), *y.items()]). It's a bit slower for me than the chain one. by superb rain, 29.08.2020 00:43
While possible, that's using the "new way" except for lists instead of dictionaries - I'm not going to suggest people are doing something we have no evidence they're doing that is clearly suboptimal... you could do even more things that are suboptimal, so I'm not going to introduce the idea. by Aaron Hall, 29.08.2020 02:31
Wow! That's a thorough answer. One minor comment, though: "the intended usage for dict(**y) is for creating dictionaries for readability purposes". I would argue that it's also to make the code less error prone, because dict(a=17, b=19, a=23) would fail with "SyntaxError: keyword argument repeated", while {"a": 17, "b": 19, "a": 23} would not (with 23 overwriting 17) and your accidental double key "a" would've gone unnoticed. Of course, if you want to allow double keys (I cannot see why, though), then {...} syntax is the way to go. Many linters, of course, warn of double keys. by Vedran Šego, 08.09.2020 15:04
@VedranŠego - There's a lot of cases where you would prefer to override. As an example - hieratical value setup. You have your base config in dictionary and overrides coming from a different dict. Doing copy & update works, but that's inconsistent API design. list+list work.... while dict+dict doesn't. by Aleksandr Panzin, 09.10.2020 18:19
@AleksandrPanzin, I said "I cannot see why [you'd want double keys in a single dict definition]". Of course you'd want proper updates between multiple dictionaries, but I don't see the purpose inside a single definition (like two "a" keys in my example). by Vedran Šego, 09.10.2020 21:22
huh; I would have expected x | y to be like {**y, **x}, not {**x, **y} by ysth, 03.11.2020 04:27
This answer is very... bloated. A significant amount is unnecessary, and just creates a wall of text stopping readers from seeing the other answers. The entire "Critiques of Other Answers" section should really be comments on the other answers... by iacob, 14.02.2021 00:05
Show remaining 16 comments
1
1683

In your case, what you can do is:

z = dict(list(x.items()) + list(y.items()))

This will, as you want it, put the final dict in z, and make the value for key b be properly overridden by the second (y) dict's value:

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

If you use Python 2, you can even remove the list() calls. To create z:

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

If you use Python version 3.9.0a4 or greater, then you can directly use:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = x | y
print(z)
{'a': 1, 'c': 11, 'b': 10}
02.09.2008 07:50
Comments
Don't use this as it is very inefficient. (See the timeit results below.) It may have been necessary in the Py2 days if a wrapper function was not an option, but those days are now past. by Gringo Suave, 11.03.2020 17:22
3
675

An alternative:

z = x.copy()
z.update(y)
02.09.2008 13:00
Comments
To clarify why this doesn't meet the critera provided by the question: it's not a single expression and it doesn't return z. by Alexander Oh, 21.03.2013 13:15
Put it this way: if you need to put two lines of comments explaining your one line of code to the people you hand your code off to...have you really done it in one line? :) I fully agree Python is not good for this: there should be a much easier way. While this answer is more pythonic, is it really all that explicit or clear? Update is not one of the "core" functions that people tend to use a lot. by eric, 19.10.2017 13:07
Well, if people insist on making it a oneliner, you can always do (lambda z: z.update(y) or z)(x.copy()) :P by towr, 24.02.2020 12:43
2
379

Another, more concise, option:

z = dict(x, **y)

Note: this has become a popular answer, but it is important to point out that if y has any non-string keys, the fact that this works at all is an abuse of a CPython implementation detail, and it does not work in Python 3, or in PyPy, IronPython, or Jython. Also, Guido is not a fan. So I can't recommend this technique for forward-compatible or cross-implementation portable code, which really means it should be avoided entirely.

02.09.2008 15:52
Comments
Works fine in Python 3 and PyPy and PyPy 3, can't speak to Jython or Iron. Given this pattern is explicitly documented (see the third constructor form in this documentation) I'd argue it's not an "implementation detail" but intentional feature use. by amcgregor, 12.04.2019 13:10
@amcgregor You missed the key phrase "if y has any non-string keys." That's what doesn't work in Python3; the fact that it works in CPython 2 is an implementation detail that can't be relied on. IFF all your keys are guaranteed to be strings, this is a fully supported option. by Carl Meyer, 10.05.2019 16:27
0
237

This probably won't be a popular answer, but you almost certainly do not want to do this. If you want a copy that's a merge, then use copy (or deepcopy, depending on what you want) and then update. The two lines of code are much more readable - more Pythonic - than the single line creation with .items() + .items(). Explicit is better than implicit.

In addition, when you use .items() (pre Python 3.0), you're creating a new list that contains the items from the dict. If your dictionaries are large, then that is quite a lot of overhead (two large lists that will be thrown away as soon as the merged dict is created). update() can work more efficiently, because it can run through the second dict item-by-item.

In terms of time:

>>> timeit.Timer("dict(x, **y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.52571702003479
>>> timeit.Timer("temp = x.copy()\ntemp.update(y)", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
15.694622993469238
>>> timeit.Timer("dict(x.items() + y.items())", "x = dict(zip(range(1000), range(1000)))\ny=dict(zip(range(1000,2000), range(1000,2000)))").timeit(100000)
41.484580039978027

IMO the tiny slowdown between the first two is worth it for the readability. In addition, keyword arguments for dictionary creation was only added in Python 2.3, whereas copy() and update() will work in older versions.

08.09.2008 11:16
1
173

In a follow-up answer, you asked about the relative performance of these two alternatives:

z1 = dict(x.items() + y.items())
z2 = dict(x, **y)

On my machine, at least (a fairly ordinary x86_64 running Python 2.5.2), alternative z2 is not only shorter and simpler but also significantly faster. You can verify this for yourself using the timeit module that comes with Python.

Example 1: identical dictionaries mapping 20 consecutive integers to themselves:

% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z1=dict(x.items() + y.items())'
100000 loops, best of 3: 5.67 usec per loop
% python -m timeit -s 'x=y=dict((i,i) for i in range(20))' 'z2=dict(x, **y)' 
100000 loops, best of 3: 1.53 usec per loop

z2 wins by a factor of 3.5 or so. Different dictionaries seem to yield quite different results, but z2 always seems to come out ahead. (If you get inconsistent results for the same test, try passing in -r with a number larger than the default 3.)

Example 2: non-overlapping dictionaries mapping 252 short strings to integers and vice versa:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z1=dict(x.items() + y.items())'
1000 loops, best of 3: 260 usec per loop
% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z2=dict(x, **y)'               
10000 loops, best of 3: 26.9 usec per loop

z2 wins by about a factor of 10. That's a pretty big win in my book!

After comparing those two, I wondered if z1's poor performance could be attributed to the overhead of constructing the two item lists, which in turn led me to wonder if this variation might work better:

from itertools import chain
z3 = dict(chain(x.iteritems(), y.iteritems()))

A few quick tests, e.g.

% python -m timeit -s 'from itertools import chain; from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z3=dict(chain(x.iteritems(), y.iteritems()))'
10000 loops, best of 3: 66 usec per loop

lead me to conclude that z3 is somewhat faster than z1, but not nearly as fast as z2. Definitely not worth all the extra typing.

This discussion is still missing something important, which is a performance comparison of these alternatives with the "obvious" way of merging two lists: using the update method. To try to keep things on an equal footing with the expressions, none of which modify x or y, I'm going to make a copy of x instead of modifying it in-place, as follows:

z0 = dict(x)
z0.update(y)

A typical result:

% python -m timeit -s 'from htmlentitydefs import codepoint2name as x, name2codepoint as y' 'z0=dict(x); z0.update(y)'
10000 loops, best of 3: 26.9 usec per loop

In other words, z0 and z2 seem to have essentially identical performance. Do you think this might be a coincidence? I don't....

In fact, I'd go so far as to claim that it's impossible for pure Python code to do any better than this. And if you can do significantly better in a C extension module, I imagine the Python folks might well be interested in incorporating your code (or a variation on your approach) into the Python core. Python uses dict in lots of places; optimizing its operations is a big deal.

You could also write this as

z0 = x.copy()
z0.update(y)

as Tony does, but (not surprisingly) the difference in notation turns out not to have any measurable effect on performance. Use whichever looks right to you. Of course, he's absolutely correct to point out that the two-statement version is much easier to understand.

23.10.2008 02:38
Comments
This does not work in Python 3; items() is not catenable, and iteritems does not exist. by Antti Haapala, 16.03.2015 05:50
4
156

In Python 3.0 and later, you can use collections.ChainMap which groups multiple dicts or other mappings together to create a single, updateable view:

>>> 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

Update for Python 3.5 and later: You can use PEP 448 extended dictionary packing and unpacking. This is fast and easy:

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

Update for Python 3.9 and later: You can use the PEP 584 union operator:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x | y
{'a': 1, 'b': 10, 'c': 11}
28.04.2013 03:15
Comments
But one should be cautious while using ChainMap there's a catch that if you have duplicate keys the values from first mapping get used and when you call a del on say a ChainMap c will delete the first mapping of that key. by Slayer, 14.02.2017 05:14
@Prerit What else would you expect it to do? That's the normal way chained namespaces work. Consider how $PATH works in bash. Deleting an executable on the path doesn't preclude another executable with the same name further upstream. by Raymond Hettinger, 15.02.2017 07:24
@Raymond Hettinger I agree, just added a caution. Most people may not know about it. :D by Slayer, 15.02.2017 15:15
@Prerit You could cast to dict to avoid that, i.e.: dict(ChainMap({}, y, x)) by wjandrea, 15.07.2019 16:30
1
137

I wanted something similar, but with the ability to specify how the values on duplicate keys were merged, so I hacked this out (but did not heavily test it). Obviously this is not a single expression, but it is a single function call.

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result
04.09.2008 19:08
Comments
Handy solution when the default behaviour of the shorter and simpler solutions (replacement of values of common keys by the second dictionary) is not wished. For Python 3, iteritems() is not available anymore in dicts, and one can simply use items() instead. by Corentor, 05.03.2021 14:22
2
108

Recursively/deep update a dict

def deepupdate(original, update):
    """
    Recursively update a dict.
    Subdict's won't be overwritten but also updated.
    """
    for key, value in original.iteritems(): 
        if key not in update:
            update[key] = value
        elif isinstance(value, dict):
            deepupdate(value, update[key]) 
    return update

Demonstration:

pluto_original = {
    'name': 'Pluto',
    'details': {
        'tail': True,
        'color': 'orange'
    }
}

pluto_update = {
    'name': 'Pluutoo',
    'details': {
        'color': 'blue'
    }
}

print deepupdate(pluto_original, pluto_update)

Outputs:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}

Thanks rednaw for edits.

29.11.2011 11:52
Comments
This does not answer the question. The question clearly asks for a new dictionary, z, from original dictionaries, x and y, with values from y replacing those of x - not an updated dictionary. This answer modifies y in-place by adding values from x. Worse, it does not copy these values, so one could further modify the modified dictionary, y, and modifications could be reflected in dictionary x. @Jérôme I hope this code is not causing any bugs for your application - at least consider using deepcopy to copy the values. by Aaron Hall, 09.11.2018 02:14
@AaronHall agreed this does not answer the question. But it answers my need. I understand those limitations, but that's not an issue in my case. Thinking of it, maybe the name is misleading, as it might evoke a deepcopy, which it does not provide. But it addresses deep nesting. Here's another implementation from the Martellibot: stackoverflow.com/questions/3232943/…. by Jérôme, 09.11.2018 13:24
2
85

Python 3.5 (PEP 448) allows a nicer syntax option:

x = {'a': 1, 'b': 1}
y = {'a': 2, 'c': 2}
final = {**x, **y} 
final
# {'a': 2, 'b': 1, 'c': 2}

Or even

final = {'a': 1, 'b': 1, **x, **y}

In Python 3.9 you also use | and |= with the below example from PEP 584

d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
26.02.2015 21:27
Comments
In what way is this solution better than the dict(x, **y)-solution? As you (@CarlMeyer) mentioned within the note of your own answer (stackoverflow.com/a/39858/2798610) Guido considers that solution illegal. by Blackeagle52, 04.03.2015 11:09
Guido dislikes dict(x, **y) for the (very good) reason that it relies on y only having keys which are valid keyword argument names (unless you are using CPython 2.7, where the dict constructor cheats). This objection/restriction does not apply to PEP 448, which generalizes the ** unpacking syntax to dict literals. So this solution has the same concision as dict(x, **y), without the downside. by Carl Meyer, 04.03.2015 22:24
0
85

The best version I could think while not using copy would be:

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

It's faster than dict(x.items() + y.items()) but not as fast as n = copy(a); n.update(b), at least on CPython. This version also works in Python 3 if you change iteritems() to items(), which is automatically done by the 2to3 tool.

Personally I like this version best because it describes fairly good what I want in a single functional syntax. The only minor problem is that it doesn't make completely obvious that values from y takes precedence over values from x, but I don't believe it's difficult to figure that out.

14.10.2010 18:55
1
74
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

For items with keys in both dictionaries ('b'), you can control which one ends up in the output by putting that one last.

02.09.2008 07:49
Comments
In python 3 you would get TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items' ... you should encapsulate each dict with list() like: dict(list(x.items()) + list(y.items())) by justSaid, 26.04.2019 08:45
5
60

While the question has already been answered several times, this simple solution to the problem has not been listed yet.

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z4 = {}
z4.update(x)
z4.update(y)

It is as fast as z0 and the evil z2 mentioned above, but easy to understand and change.

14.10.2011 16:12
Comments
but it's three statements rather than one expression by fortran, 18.10.2011 15:44
Yes! The mentioned one-expression-solutions are either slow or evil. Good code is readable and maintainable. So the problem is the question not the answer. We should ask for the best solution of a problem not for a one-line-solution. by phobie, 28.10.2011 03:36
Lose the z4 = {} and change the next line to z4 = x.copy() -- better than just good code doesn't do unnecessary things (which makes it even more readable and maintainable). by martineau, 08.03.2013 15:10
Your suggestion would change this to Matthews answer. While his answer is fine, I think mine is more readable and better maintainable. The extra line would only be bad if it would cost execution time. by phobie, 06.05.2013 11:50
I suggest you put this into a function by Corman, 14.06.2020 23:16
0
55
def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Among such shady and dubious answers, this shining example is the one and only good way to merge dicts in Python, endorsed by dictator for life Guido van Rossum himself! Someone else suggested half of this, but did not put it in a function.

print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

gives:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
06.08.2012 09:24
0
50

If you think lambdas are evil then read no further. As requested, you can write the fast and memory-efficient solution with one expression:

x = {'a':1, 'b':2}
y = {'b':10, 'c':11}
z = (lambda a, b: (lambda a_copy: a_copy.update(b) or a_copy)(a.copy()))(x, y)
print z
{'a': 1, 'c': 11, 'b': 10}
print x
{'a': 1, 'b': 2}

As suggested above, using two lines or writing a function is probably a better way to go.

23.11.2011 18:08
2
44

Be pythonic. Use a comprehension:

z={i:d[i] for d in [x,y] for i in d}

>>> print z
{'a': 1, 'c': 11, 'b': 10}
20.01.2016 11:46
Comments
As a function: def dictmerge(*args): return {i:d[i] for d in args for i in d} by jessexknight, 06.06.2018 18:27
Save a lookup by iterating the key/value pairs directly: z={k: v for d in (x, y) for k, v in d.items()} by ShadowRanger, 05.03.2019 19:33
0
39

In python3, the items method no longer returns a list, but rather a view, which acts like a set. In this case you'll need to take the set union since concatenating with + won't work:

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

For python3-like behavior in version 2.7, the viewitems method should work in place of items:

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

I prefer this notation anyways since it seems more natural to think of it as a set union operation rather than concatenation (as the title shows).

Edit:

A couple more points for python 3. First, note that the dict(x, **y) trick won't work in python 3 unless the keys in y are strings.

Also, Raymond Hettinger's Chainmap answer is pretty elegant, since it can take an arbitrary number of dicts as arguments, but from the docs it looks like it sequentially looks through a list of all the dicts for each lookup:

Lookups search the underlying mappings successively until a key is found.

This can slow you down if you have a lot of lookups in your application:

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

So about an order of magnitude slower for lookups. I'm a fan of Chainmap, but looks less practical where there may be many lookups.

09.10.2013 18:09
0
30

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))

sum has bad performance. See https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

17.10.2012 02:09
0
29

Simple solution using itertools that preserves order (latter dicts have precedence)

# py2
from itertools import chain, imap
merge = lambda *args: dict(chain.from_iterable(imap(dict.iteritems, args)))

# py3
from itertools import chain
merge = lambda *args: dict(chain.from_iterable(map(dict.items, args)))

And it's usage:

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

>>> z = {'c': 3, 'd': 4}
>>> merge(x, y, z)
{'a': 1, 'b': 10, 'c': 3, 'd': 4}
04.08.2015 14:54
0
27

Abuse leading to a one-expression solution for Matthew's answer:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (lambda f=x.copy(): (f.update(y), f)[1])()
>>> z
{'a': 1, 'c': 11, 'b': 10}

You said you wanted one expression, so I abused lambda to bind a name, and tuples to override lambda's one-expression limit. Feel free to cringe.

You could also do this of course if you don't care about copying it:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}
07.08.2013 21:23
0
22

Even though the answers were good for this shallow dictionary, none of the methods defined here actually do a deep dictionary merge.

Examples follow:

a = { 'one': { 'depth_2': True }, 'two': True }
b = { 'one': { 'extra': False } }
print dict(a.items() + b.items())

One would expect a result of something like this:

{ 'one': { 'extra': False', 'depth_2': True }, 'two': True }

Instead, we get this:

{'two': True, 'one': {'extra': False}}

The 'one' entry should have had 'depth_2' and 'extra' as items inside its dictionary if it truly was a merge.

Using chain also, does not work:

from itertools import chain
print dict(chain(a.iteritems(), b.iteritems()))

Results in:

{'two': True, 'one': {'extra': False}}

The deep merge that rcwesick gave also creates the same result.

Yes, it will work to merge the sample dictionaries, but none of them are a generic mechanism to merge. I'll update this later once I write a method that does a true merge.

03.08.2012 23:36
0
18

If you don't mind mutating x,

x.update(y) or x

Simple, readable, performant. You know update() always returns None, which is a false value. So the above expression will always evaluate to x, after updating it.

Most mutating methods in the standard library (like .update()) return None by convention, so this kind of pattern will work on those too. However, if you're using a dict subclass or some other method that doesn't follow this convention, then or may return its left operand, which may not be what you want. Instead, you can use a tuple display and index, which works regardless of what the first element evaluates to (although it's not quite as pretty):

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

If you don't have x in a variable yet, you can use lambda to make a local without using an assignment statement. This amounts to using lambda as a let expression, which is a common technique in functional languages, but maybe unpythonic.

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

Although it's not that different from the following use of the new walrus operator (Python 3.8+ only):

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

If you do want a copy, PEP 584 style x | y is the most Pythonic on 3.9+. If you must support older versions, PEP 448 style {**x, **y} is easiest for 3.5+. But if that's not available in your (even older) Python version, the let pattern works here too.

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

(That is, of course, nearly equivalent to (z := x.copy()).update(y) or z, but if your Python version is new enough for that, then the PEP 448 style will be available.)

22.09.2017 02:57
0
15

(For Python2.7* only; there are simpler solutions for Python3*.)

If you're not averse to importing a standard library module, you can do

from functools import reduce

def merge_dicts(*dicts):
    return reduce(lambda a, d: a.update(d) or a, dicts, {})

(The or a bit in the lambda is necessary because dict.update always returns None on success.)

28.03.2016 13:13
0
15

It's so silly that .update returns nothing.
I just use a simple helper function to solve the problem:

def merge(dict1,*dicts):
    for dict2 in dicts:
        dict1.update(dict2)
    return dict1

Examples:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy
02.03.2014 01:44
1
14

The problem I have with solutions listed to date is that, in the merged dictionary, the value for key "b" is 10 but, to my way of thinking, it should be 12. In that light, I present the following:

import timeit

n=100000
su = """
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
"""

def timeMerge(f,su,niter):
    print "{:4f} sec for: {:30s}".format(timeit.Timer(f,setup=su).timeit(n),f)

timeMerge("dict(x, **y)",su,n)
timeMerge("x.update(y)",su,n)
timeMerge("dict(x.items() + y.items())",su,n)
timeMerge("for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k] ",su,n)

#confirm for loop adds b entries together
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]
print "confirm b elements are added:",x

Results:

0.049465 sec for: dict(x, **y)
0.033729 sec for: x.update(y)                   
0.150380 sec for: dict(x.items() + y.items())   
0.083120 sec for: for k in y.keys(): x[k] = k in x and x[k]+y[k] or y[k]

confirm b elements are added: {'a': 1, 'c': 11, 'b': 12}
03.12.2013 18:11
Comments
You might be interested in cytoolz.merge_with (toolz.readthedocs.io/en/latest/…) by bli, 16.02.2017 13:44
0
14

Drawing on ideas here and elsewhere I've comprehended a function:

def merge(*dicts, **kv): 
      return { k:v for d in list(dicts) + [kv] for k,v in d.items() }

Usage (tested in python 3):

assert (merge({1:11,'a':'aaa'},{1:99, 'b':'bbb'},foo='bar')==\
    {1: 99, 'foo': 'bar', 'b': 'bbb', 'a': 'aaa'})

assert (merge(foo='bar')=={'foo': 'bar'})

assert (merge({1:11},{1:99},foo='bar',baz='quux')==\
    {1: 99, 'foo': 'bar', 'baz':'quux'})

assert (merge({1:11},{1:99})=={1: 99})

You could use a lambda instead.

19.07.2013 05:49
0
13
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

This should solve your problem.

30.11.2015 13:04
0
15

New in Python 3.9: Use the union operator (|) to merge dicts similar to sets:

>>> d = {'a': 1, 'b': 2}
>>> e = {'a': 9, 'c': 3}
>>> d | e
{'a': 9, 'b': 2, 'c': 3}

For matching keys, the right dict takes precedence.

This also works for |= to modify a dict in-place:

>>> e |= d    # e = e | d
>>> e
{'a': 1, 'c': 3, 'b': 2}
01.06.2020 21:23
1
9
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}
13.11.2013 10:01
Comments
This method overwrites x with its copy. If x is a function argument this won't work (see example) by bartolo-otrit, 22.02.2019 09:27
2
11

This can be done with a single dict comprehension:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> { key: y[key] if key in y else x[key]
      for key in set(x) + set(y)
    }

In my view the best answer for the 'single expression' part as no extra functions are needed, and it is short.

17.07.2015 14:47
Comments
I suspect performance will not be very good though; creating a set out of each dict then only iterating through the keys means another lookup for the value each time (though relatively fast, still increases the order of the function for scaling) by Breezer, 16.02.2017 14:57
it all depends on the version of the python we are using. In 3.5 and above {**x,**y} gives the concatenated dictionary by Rashid Mv, 23.12.2017 15:50
0
13

There will be a new option when Python 3.8 releases (scheduled for 20 October, 2019), thanks to PEP 572: Assignment Expressions. The new assignment expression operator := allows you to assign the result of the copy and still use it to call update, leaving the combined code a single expression, rather than two statements, changing:

newdict = dict1.copy()
newdict.update(dict2)

to:

(newdict := dict1.copy()).update(dict2)

while behaving identically in every way. If you must also return the resulting dict (you asked for an expression returning the dict; the above creates and assigns to newdict, but doesn't return it, so you couldn't use it to pass an argument to a function as is, a la myfunc((newdict := dict1.copy()).update(dict2))), then just add or newdict to the end (since update returns None, which is falsy, it will then evaluate and return newdict as the result of the expression):

(newdict := dict1.copy()).update(dict2) or newdict

Important caveat: In general, I'd discourage this approach in favor of:

newdict = {**dict1, **dict2}

The unpacking approach is clearer (to anyone who knows about generalized unpacking in the first place, which you should), doesn't require a name for the result at all (so it's much more concise when constructing a temporary that is immediately passed to a function or included in a list/tuple literal or the like), and is almost certainly faster as well, being (on CPython) roughly equivalent to:

newdict = {}
newdict.update(dict1)
newdict.update(dict2)

but done at the C layer, using the concrete dict API, so no dynamic method lookup/binding or function call dispatch overhead is involved (where (newdict := dict1.copy()).update(dict2) is unavoidably identical to the original two-liner in behavior, performing the work in discrete steps, with dynamic lookup/binding/invocation of methods.

It's also more extensible, as merging three dicts is obvious:

 newdict = {**dict1, **dict2, **dict3}

where using assignment expressions won't scale like that; the closest you could get would be:

 (newdict := dict1.copy()).update(dict2), newdict.update(dict3)

or without the temporary tuple of Nones, but with truthiness testing of each None result:

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)

either of which is obviously much uglier, and includes further inefficiencies (either a wasted temporary tuple of Nones for comma separation, or pointless truthiness testing of each update's None return for or separation).

The only real advantage to the assignment expression approach occurs if:

  1. You have generic code that needs handle both sets and dicts (both of them support copy and update, so the code works roughly as you'd expect it to)
  2. You expect to receive arbitrary dict-like objects, not just dict itself, and must preserve the type and semantics of the left hand side (rather than ending up with a plain dict). While myspecialdict({**speciala, **specialb}) might work, it would involve an extra temporary dict, and if myspecialdict has features plain dict can't preserve (e.g. regular dicts now preserve order based on the first appearance of a key, and value based on the last appearance of a key; you might want one that preserves order based on the last appearance of a key so updating a value also moves it to the end), then the semantics would be wrong. Since the assignment expression version uses the named methods (which are presumably overloaded to behave appropriately), it never creates a dict at all (unless dict1 was already a dict), preserving the original type (and original type's semantics), all while avoiding any temporaries.
28.02.2019 17:16
1
5

Using a dict comprehension, you may

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

dc = {xi:(x[xi] if xi not in list(y.keys()) 
           else y[xi]) for xi in list(x.keys())+(list(y.keys()))}

gives

>>> dc
{'a': 1, 'c': 11, 'b': 10}

Note the syntax for if else in comprehension

{ (some_key if condition else default_key):(something_if_true if condition 
          else something_if_false) for key, value in dict_.items() }
27.05.2013 09:04
Comments
I like the idea of using a dict comprehension, but your implementation is weak. It is insane to use ... in list(y.keys()) instead of just ... in y. by wim, 18.02.2014 20:18
2
8

I know this does not really fit the specifics of the questions ("one liner"), but since none of the answers above went into this direction while lots and lots of answers addressed the performance issue, I felt I should contribute my thoughts.

Depending on the use case it might not be necessary to create a "real" merged dictionary of the given input dictionaries. A view which does this might be sufficient in many cases, i. e. an object which acts like the merged dictionary would without computing it completely. A lazy version of the merged dictionary, so to speak.

In Python, this is rather simple and can be done with the code shown at the end of my post. This given, the answer to the original question would be:

z = MergeDict(x, y)

When using this new object, it will behave like a merged dictionary but it will have constant creation time and constant memory footprint while leaving the original dictionaries untouched. Creating it is way cheaper than in the other solutions proposed.

Of course, if you use the result a lot, then you will at some point reach the limit where creating a real merged dictionary would have been the faster solution. As I said, it depends on your use case.

If you ever felt you would prefer to have a real merged dict, then calling dict(z) would produce it (but way more costly than the other solutions of course, so this is just worth mentioning).

You can also use this class to make a kind of copy-on-write dictionary:

a = { 'x': 3, 'y': 4 }
b = MergeDict(a)  # we merge just one dict
b['x'] = 5
print b  # will print {'x': 5, 'y': 4}
print a  # will print {'y': 4, 'x': 3}

Here's the straight-forward code of MergeDict:

class MergeDict(object):
  def __init__(self, *originals):
    self.originals = ({},) + originals[::-1]  # reversed

  def __getitem__(self, key):
    for original in self.originals:
      try:
        return original[key]
      except KeyError:
        pass
    raise KeyError(key)

  def __setitem__(self, key, value):
    self.originals[0][key] = value

  def __iter__(self):
    return iter(self.keys())

  def __repr__(self):
    return '%s(%s)' % (
      self.__class__.__name__,
      ', '.join(repr(original)
          for original in reversed(self.originals)))

  def __str__(self):
    return '{%s}' % ', '.join(
        '%r: %r' % i for i in self.iteritems())

  def iteritems(self):
    found = set()
    for original in self.originals:
      for k, v in original.iteritems():
        if k not in found:
          yield k, v
          found.add(k)

  def items(self):
    return list(self.iteritems())

  def keys(self):
    return list(k for k, _ in self.iteritems())

  def values(self):
    return list(v for _, v in self.iteritems())
18.05.2016 15:57
Comments
I saw by now that some answers refer to a class called ChainMap which is available in Python 3 only and which does more or less what my code does. So shame on me for not reading everything carefully enough. But given that this only exists for Python 3, please take my answer as a contribution for the Python 2 users ;-) by Alfe, 18.05.2016 16:10
ChainMap was backported for earlier Pythons: pypi.python.org/pypi/chainmap by clacke, 28.07.2016 11:19
0
4

You can use toolz.merge([x, y]) for this.

18.11.2016 12:53
1
5

I was curious if I could beat the accepted answer's time with a one line stringify approach:

I tried 5 methods, none previously mentioned - all one liner - all producing correct answers - and I couldn't come close.

So... to save you the trouble and perhaps fulfill curiosity:

import json
import yaml
import time
from ast import literal_eval as literal

def merge_two_dicts(x, y):
    z = x.copy()   # start with x's keys and values
    z.update(y)    # modifies z with y's keys and values & returns None
    return z

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

start = time.time()
for i in range(10000):
    z = yaml.load((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify yaml')

start = time.time()
for i in range(10000):
    z = literal((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify literal')

start = time.time()
for i in range(10000):
    z = eval((str(x)+str(y)).replace('}{',', '))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify eval')

start = time.time()
for i in range(10000):
    z = {k:int(v) for k,v in (dict(zip(
            ((str(x)+str(y))
            .replace('}',' ')
            .replace('{',' ')
            .replace(':',' ')
            .replace(',',' ')
            .replace("'",'')
            .strip()
            .split('  '))[::2], 
            ((str(x)+str(y))
            .replace('}',' ')
            .replace('{',' ').replace(':',' ')
            .replace(',',' ')
            .replace("'",'')
            .strip()
            .split('  '))[1::2]
             ))).items()}
elapsed = (time.time()-start)
print (elapsed, z, 'stringify replace')

start = time.time()
for i in range(10000):
    z = json.loads(str((str(x)+str(y)).replace('}{',', ').replace("'",'"')))
elapsed = (time.time()-start)
print (elapsed, z, 'stringify json')

start = time.time()
for i in range(10000):
    z = merge_two_dicts(x, y)
elapsed = (time.time()-start)
print (elapsed, z, 'accepted')

results:

7.693928956985474 {'c': 11, 'b': 10, 'a': 1} stringify yaml
0.29134678840637207 {'c': 11, 'b': 10, 'a': 1} stringify literal
0.2208399772644043 {'c': 11, 'b': 10, 'a': 1} stringify eval
0.1106564998626709 {'c': 11, 'b': 10, 'a': 1} stringify replace
0.07989692687988281 {'c': 11, 'b': 10, 'a': 1} stringify json
0.005082368850708008 {'c': 11, 'b': 10, 'a': 1} accepted

What I did learn from this is that JSON approach is the fastest way (of those attempted) to return a dictionary from string-of-dictionary; much faster (about 1/4th of the time) of what I considered to be the normal method using ast. I also learned that, the YAML approach should be avoided at all cost.

Yes, I understand that this is not the best/correct way. I was curious if it was faster, and it isn't; I posted to prove it so.

22.03.2018 04:08
Comments
Note that the json approach is faster than ast.literal_eval, but it's also not as comprehensive. It can't handle Python literals not in the JSON spec, so no tuples, sets, frozensets, bools (it can handle JSON bools, but not the result of stringifying a Python bool directly), etc. ast.literal_eval is slower, but at least some of that is a consequence of handling more complex inputs. That said, I'm pretty sure it could be faster if they bothered to optimize it, it's just pretty rare that evaluating strings of Python literals is the chokepoint in code. by ShadowRanger, 28.02.2019 17:29
0
7

In Python 3.9

Based on PEP 584, the new version of Python introduces two new operators for dictionaries: union (|) and in-place union (|=). You can use | to merge two dictionaries, while |= will update a dictionary in place:

>>> pycon = {2016: "Portland", 2018: "Cleveland"}
>>> europython = {2017: "Rimini", 2018: "Edinburgh", 2019: "Basel"}

>>> pycon | europython
{2016: 'Portland', 2018: 'Edinburgh', 2017: 'Rimini', 2019: 'Basel'}

>>> pycon |= europython
>>> pycon
{2016: 'Portland', 2018: 'Edinburgh', 2017: 'Rimini', 2019: 'Basel'}

If d1 and d2 are two dictionaries, then d1 | d2 does the same as {**d1, **d2}. The | operator is used for calculating the union of sets, so the notation may already be familiar to you.

One advantage of using | is that it works on different dictionary-like types and keeps the type through the merge:

>>> from collections import defaultdict
>>> europe = defaultdict(lambda: "", {"Norway": "Oslo", "Spain": "Madrid"})
>>> africa = defaultdict(lambda: "", {"Egypt": "Cairo", "Zimbabwe": "Harare"})

>>> europe | africa
defaultdict(<function <lambda> at 0x7f0cb42a6700>,
  {'Norway': 'Oslo', 'Spain': 'Madrid', 'Egypt': 'Cairo', 'Zimbabwe': 'Harare'})

>>> {**europe, **africa}
{'Norway': 'Oslo', 'Spain': 'Madrid', 'Egypt': 'Cairo', 'Zimbabwe': 'Harare'}

You can use a defaultdict when you want to effectively handle missing keys. Note that | preserves the defaultdict, while {**europe, **africa} does not.

There are some similarities between how | works for dictionaries and how + works for lists. In fact, the + operator was originally proposed to merge dictionaries as well. This correspondence becomes even more evident when you look at the in-place operator.

The basic use of |= is to update a dictionary in place, similar to .update():

>>> libraries = {
...     "collections": "Container datatypes",
...     "math": "Mathematical functions",
... }
>>> libraries |= {"zoneinfo": "IANA time zone support"}
>>> libraries
{'collections': 'Container datatypes', 'math': 'Mathematical functions',
 'zoneinfo': 'IANA time zone support'}

When you merge dictionaries with |, both dictionaries need to be of a proper dictionary type. On the other hand, the in-place operator (|=) is happy to work with any dictionary-like data structure:

>>> libraries |= [("graphlib", "Functionality for graph-like structures")]
>>> libraries
{'collections': 'Container datatypes', 'math': 'Mathematical functions',
 'zoneinfo': 'IANA time zone support',
 'graphlib': 'Functionality for graph-like structures'}
06.10.2020 15:23
2
4

A union of the OP's two dictionaries would be something like:

{'a': 1, 'b': 2, 10, 'c': 11}

Specifically, the union of two entities(x and y) contains all the elements of x and/or y. Unfortunately, what the OP asks for is not a union, despite the title of the post.

My code below is neither elegant nor a one-liner, but I believe it is consistent with the meaning of union.

From the OP's example:

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

z = {}
for k, v in x.items():
    if not k in z:
        z[k] = [(v)]
    else:
        z[k].append((v))
for k, v in y.items():
    if not k in z:
        z[k] = [(v)]
    else:
        z[k].append((v))

{'a': [1], 'b': [2, 10], 'c': [11]}

Whether one wants lists could be changed, but the above will work if a dictionary contains lists (and nested lists) as values in either dictionary.

30.09.2014 02:36
Comments
I've edited the question to not use the word union, for clarity. by Carl Meyer, 30.09.2014 15:49
Perhaps you mean {'a': 1, 'b': (2, 10), 'c': 11} …? by Alfe, 18.05.2016 16:07
3
1

I have a solution which is not specified here

z = {}
z.update(x) or z.update(y)

This will not update x as well as y. Performance? I don't think it will be terribly slow.

05.12.2013 08:02
Comments
Noooo, it's still 2 lines and also longer than z = x.copy(); z.update(y) by Navin, 11.12.2013 09:50
... or z. Otherwise it returns None. by clacke, 07.04.2018 12:20
I am not assigning th update operations to z :-) But got an idea to make them single liner.. Thanks. by thiruvenkadam, 27.06.2018 07:43
1
6

Python 3.9+ only

Merge (|) and update (|=) operators have been added to the built-in dict class.

>>> d = {'spam': 1, 'eggs': 2, 'cheese': 3}
>>> e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
>>> d | e
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

The augmented assignment version operates in-place:

>>> d |= e
>>> d
{'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}

See PEP 584

09.04.2020 08:20
Comments
And for list of dicts: merged = {}; merged = [merged | d for d in dict_list] by Daniel Braun, 07.05.2020 15:39
0
1

The question is tagged python-3x but, taking into account that it's a relatively recent addition and that the most voted, accepted answer deals extensively with a Python 2.x solution, I dare add a one liner that draws on an irritating feature of Python 2.x list comprehension, that is name leaking...

$ python2
Python 2.7.13 (default, Jan 19 2017, 14:48:08) 
[GCC 6.3.0 20170118] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> [z.update(d) for z in [{}] for d in (x, y)]
[None, None]
>>> z
{'a': 1, 'c': 11, 'b': 10}
>>> ...

I'm happy to say that the above doesn't work any more on any version of Python 3.

30.05.2017 12:28
0
4

This is an expression for Python 3.5 or greater that merges dictionaries using reduce:

>>> from functools import reduce
>>> l = [{'a': 1}, {'b': 2}, {'a': 100, 'c': 3}]
>>> reduce(lambda x, y: {**x, **y}, l, {})
{'a': 100, 'b': 2, 'c': 3}

Note: this works even if the dictionary list is empty or contains only one element.

15.04.2018 23:02
1
5

For Python 3:

from collections import ChainMap
a = {"a":1, "b":2}
b = {"c":5, "d":8}
dict(ChainMap(a, b))  # {"a":1, "b":2, "c":5, "d":8}

If you have the same key in both dictionaries, ChainMap will use the first key's value and ignores the second key's value. Cheers!

31.05.2019 17:10
Comments
This should be the correct solution. Note that earlier input parameters have precedence and dictionaries are taken by reference, i.e. the ChainMap will get updated if the map gets updated. by Romeo Valentin, 23.07.2019 16:31
0
5

I benchmarked the suggested with perfplot and found that the good old

temp = x.copy()
temp.update(y)

is the fastest solution together with the new

x | y

enter image description here


Code to reproduce the plot:

from collections import ChainMap
from itertools import chain
import perfplot


def setup(n):
    x = dict(zip(range(n), range(n)))
    y = dict(zip(range(n, 2 * n), range(n, 2 * n)))
    return x, y


def copy_update(data):
    x, y = data
    temp = x.copy()
    temp.update(y)
    return temp


def add_items(data):
    x, y = data
    return dict(list(x.items()) + list(y.items()))


def curly_star(data):
    x, y = data
    return {**x, **y}


def chain_map(data):
    x, y = data
    return dict(ChainMap({}, y, x))


def itertools_chain(data):
    x, y = data
    return dict(chain(x.items(), y.items()))


def python39_concat(data):
    x, y = data
    return x | y


perfplot.show(
    setup=setup,
    kernels=[
        copy_update,
        add_items,
        curly_star,
        chain_map,
        itertools_chain,
        python39_concat,
    ],
    labels=[
        "copy_update",
        "dict(list(x.items()) + list(y.items()))",
        "{**x, **y}",
        "chain_map",
        "itertools.chain",
        "x | y",
    ],
    n_range=[2 ** k for k in range(15)],
    xlabel="len(x), len(y)",
    equality_check=None,
)
09.07.2020 17:35
0
1

I think my ugly one-liners are just necessary here.

z = next(z.update(y) or z for z in [x.copy()])
# or
z = (lambda z: z.update(y) or z)(x.copy())
  1. Dicts are merged.
  2. Single expression.
  3. Don't ever dare to use it.

P.S. This is a solution working in both versions of Python. I know that Python 3 has this {**x, **y} thing and it is the right thing to use (as well as moving to Python 3 if you still have Python 2 is the right thing to do).

11.05.2018 10:00
3
0

As of Python 3.9, PEP584, there is a new method available for this:

z = x.union(y)

now works as you desire, without modifying either x or y.

y values will override x values with the same key.

You can also now use the union merge syntax for this:

z = x | y

which gives the same result.

06.10.2020 06:24
Comments
Could you, please, provide a link to the documentation entry with the dict.union method? by Georgy, 06.10.2020 08:35
@Georgy: er.. no. Looks like they haven't been update yet to include dict.union. However they do include the d | other syntax for dictionary unions - below d.values (but it has no html anchor). I moved the whatsnew announcement link to the top. by naught101, 07.10.2020 21:37
I'd love to know why this is being downvoted. It answers the question, and assuming you can use python 3.9+, it's a better answer than all of the others. by naught101, 13.10.2020 02:32
0
1

Some ways to solve it without using any python modules (no dependencies) with few lines of codes.

ALL Python Versions (using Lambda):

merge_dicts = lambda old, new: old.update(new) or old

Python Version >= 3.5:

def merge_dicts(old, new):
    return {**old, **new} 

Older Python Version:

def merge_dicts(old, new):
    merged = old.copy()
    merged.update(new)
    return merged

This example will merge old and new while erasing old values with the new values.

USAGE:

old = {'name': 'Kevin', 'phone_number': '+33 12 34 45 67'}
new = {'name': 'Kevin', 'phone_number': '+33 88 88 88 88'}

print(merge_dicts(old, new))

OUTPUT:

{'name': 'Kevin', 'phone_number': '+33 88 88 88 88'}

IF you have to deal with multiples merged from old to new version, without losing any data one example approach below using an array of dictionaries:

ALL Python Versions:

def merge_dicts(old, news):
    merged = old.copy()
    for new in news:
        merged.update(new)
    return merged

USAGE:

old = {'name': 'Kevin', 'phone_number': '+33 12 34 45 67'}
new_01 = {'name': 'Kevin', 'phone_number': '+33 77 77 77 77', 'age': 28}
new_02 = {'name': 'SabK', 'phone_number': '+33 88 88 88 89'}
new_03 = {'phone_number': '+33 99 99 99 99'}

print(merge_dicts(old, [new_01, new_02, new_03]))

OUTPUT:

{'phone_number': '+33 99 99 99 99', 'age': 28, 'name': 'SabK'}

In this example, the new dictionary will be generated from the old one (first argument) and then will update sequentially from the first element of the array to the last one (new_01 > new_02 > new_03)

At the end, you will get all the datas from all the dictionary will updating values that as been change. This function can be really useful when you have deal with datas that change frequently.

06.12.2019 22:46
1
0

As of Python 3.9 you can use the | operator to concatenate two dictionaries.


For example,

>>> dict1 = {'a': 1, 'b': 2}
>>> dict2 = {'b': 3, 'c': 4, 'd': 5}
>>> dict1 | dict2
{'a': 1, 'b': 3, 'c': 4, 'd': 5}
29.04.2021 11:00
Comments
Also, I think this was added sometime back. See link below..... stackoverflow.com/questions/38987/… by Joe Ferndz, 29.04.2021 23:41
0
0

Instead, if, say, you want to combine the two dictionaries by adding the values, we could rely on the Collections module (I am not sure whether this existed 12 years ago - when the question was first asked):

from collections import Counter
x = Counter({'a': 1, 'b': 2})
y = Counter({'b': 10, 'c': 11})

Then x + y equates to

Counter({'a': 1, 'b': 12, 'c': 11})
11.10.2020 23:42
0
0

A hacky one-liner for 2.5+ :

>>> a = dict(x=2, y=3)
>>> b = dict(y=4, z=5)
>>> c = 'No Effect' if a.update(b) else a
>>> c
{'x': 2, 'y': 4, 'z': 5}

Things to keep in mind:

  • dict.update modifies the dict in-place, hence it evaluates to None
  • In expression A if C else B, C is evaluated first. See here

So here, a.update(b) is evaluated first, a gets updated with b and operation results in None, thus the expression will always return the value given in the else condition, i.e. a. Since, a is already modified, it will return the new value of a, which is the updated dict.

IMPROVEMENT

This can be further improved, and it be made to work for even older versions (probably python 1.0 as well?):

>>> c = a.update(b) or a

Here also, the first part produces None, hence it always returns the second part, but as the update operation is already done, it always returns the updated dict.

CRITIQUE

  • Both the solution modify the value of a, so if one wants to keep both the input dictionaries unchanged, this is not a good idea.

IMPROVEMENT

If copy of a is needed, the second one can be slightly modified:

>>> a = dict(x=2, y=3)
>>> b = dict(y=4, z=5)
>>> a, c = a.copy(), a.update(b) or a
>>> c
{'x': 2, 'y': 4, 'z': 5}
>>> d = dict(m=10, n=11)
>>> a, c = a.copy(), a.update(b) or a.update(d) or a
>>> c
{'x': 2, 'y': 4, 'z': 5, 'm': 10, 'n': 11}
>>> a
{'x': 2, 'y': 4}

CAVEATS

  • It (especially the first one) gets ugly and impractical for any number of dicts greater than 2
  • Furthermore, this is not explicit, which is un-pythonic.

Even though these solutions are extremely fast, especially the or method which is probably faster than the new python 3.9 union operator (not entirely sure, further testing required, if anyone wants to add it afterwards, they are welcome), I would not recommend these methods due to the abovementioned reasons. Added it for the sake of completeness.

22.01.2021 10:53