Quiero fusionar dos diccionarios en un nuevo diccionario.

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

z = merge(x, y)

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

El uso de x.update(y)modificaciones xen el lugar en lugar de crear un nuevo diccionario. También quiero que el manejo de conflictos sea el último en ganar dict.update().

respuesta

¿Cómo puedo fusionar dos diccionarios de Python en una sola expresión?

Para los diccionarios xy y, su diccionario fusionado superficialmente ztoma valores de y, reemplazando los de x.

  • En Python 3.9.0 o superior (lanzado el 17 de octubre de 2020 PEP-584, discutido aquí ):

    z = x | y
    
  • En Python 3.5 o superior:

    z = {**x, **y}
    
  • En Python 2, (o 3.4 o inferior) escriba una función:

    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
    

    y ahora:

    z = merge_two_dicts(x, y)
    

Explicación

Digamos que tiene dos diccionarios y desea fusionarlos en un diccionario nuevo sin alterar los diccionarios originales:

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

El resultado deseado es obtener un nuevo diccionario ( z) con los valores combinados y los valores del segundo diccionario sobrescribiendo los del primero.

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

Una nueva sintaxis para esto, propuesta en PEP 448 y disponible a partir de Python 3.5 , es

z = {**x, **y}

Y de hecho es una sola expresión.

Tenga en cuenta que también podemos fusionarnos con notación literal:

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

y ahora:

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

Ahora se muestra como implementado en el programa de lanzamiento de 3.5, PEP 478 , y ahora se ha abierto paso en el documento What's New in Python 3.5 .

Sin embargo, dado que muchas organizaciones aún utilizan Python 2, es posible que desee hacerlo de forma compatible con versiones anteriores. La forma clásica de Pythonic, disponible en Python 2 y Python 3.0-3.4, es hacer esto como un proceso de dos pasos:

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

En ambos enfoques, yocupará el segundo lugar y sus valores reemplazarán xlos valores de , por lo que bapuntará a 3nuestro resultado final.

Todavía no en Python 3.5, pero quiero una sola expresión

Si aún no está en Python 3.5 o necesita escribir un código compatible con versiones anteriores, y quiere esto en una sola expresión , el mejor rendimiento, mientras que el enfoque correcto es ponerlo en una función:

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

y luego tienes una sola expresión:

z = merge_two_dicts(x, y)

También puede crear una función para fusionar un número arbitrario de diccionarios, desde cero hasta un número muy grande:

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

Esta función funcionará en Python 2 y 3 para todos los diccionarios. por ejemplo, diccionarios dados aa g:

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

y los pares clave-valor en gtendrán prioridad sobre los diccionarios aen f, y así sucesivamente.

Críticas de otras respuestas

No use lo que ve en la respuesta anteriormente aceptada:

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

En Python 2, crea dos listas en la memoria para cada dictado, crea una tercera lista en la memoria con una longitud igual a la longitud de las dos primeras juntas y luego descarta las tres listas para crear el dictado. En Python 3, esto fallará porque está agregando dos dict_itemsobjetos juntos, no dos listas:

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

y tendría que crearlos explícitamente como listas, por ejemplo z = dict(list(x.items()) + list(y.items())). Esto es un desperdicio de recursos y poder de cómputo.

De manera similar, tomar la unión de items()en Python 3 ( viewitems()en Python 2.7) también fallará cuando los valores sean objetos que no se pueden modificar (como listas, por ejemplo). Incluso si sus valores son hashable, dado que los conjuntos están desordenados semánticamente, el comportamiento no está definido con respecto a la precedencia. Así que no hagas esto:

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

Este ejemplo demuestra lo que sucede cuando los valores no se pueden modificar:

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

Aquí hay un ejemplo en el que ydebería tener prioridad, pero en su lugar el valor de xse retiene debido al orden arbitrario de los conjuntos:

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

Otro truco que no debes usar:

z = dict(x, **y)

Esto usa el dictconstructor y es muy rápido y eficiente en memoria (incluso un poco más que nuestro proceso de dos pasos), pero a menos que sepa exactamente lo que está sucediendo aquí (es decir, el segundo dict se pasa como argumentos de palabra clave al constructor dict ), es difícil de leer, no es el uso previsto, por lo que no es Pythonic.

Aquí hay un ejemplo del uso que se está remediando en django .

Los diccionarios están pensados ​​para tomar claves hashable (por ejemplo frozenset, s o tuplas), pero este método falla en Python 3 cuando las claves no son cadenas.

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

De la lista de correo , Guido van Rossum, el creador del lenguaje, escribió:

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

y

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.

Tengo entendido (así como el entendimiento del creador del idioma ) que el uso previsto dict(**y)es para crear diccionarios con fines de legibilidad, por ejemplo:

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

en vez de

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

Respuesta a comentarios

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.

Nuevamente, no funciona para 3 cuando las claves no son cadenas. El contrato de llamada implícito es que los espacios de nombres toman diccionarios ordinarios, mientras que los usuarios solo deben pasar argumentos de palabras clave que son cadenas. Todos los demás exigibles lo hicieron cumplir. dictrompió esta consistencia en 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}

Esta inconsistencia fue mala debido a otras implementaciones de Python (PyPy, Jython, IronPython). Por lo tanto, se solucionó en Python 3, ya que este uso podría ser un cambio importante.

Les afirmo que es una incompetencia malintencionada escribir código de manera intencional que solo funciona en una versión de un idioma o que solo funciona con ciertas restricciones arbitrarias.

Más comentarios:

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

Mi respuesta: merge_two_dicts(x, y)en realidad me parece mucho más claro, si realmente nos preocupa la legibilidad. Y no es compatible con versiones posteriores, ya que Python 2 está cada vez más en desuso.

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

Sí. Debo remitirlo a la pregunta, que solicita una fusión superficial de dos diccionarios, con los valores del primero sobrescritos por los del segundo, en una sola expresión.

Suponiendo dos diccionarios de diccionarios, uno podría fusionarlos recursivamente en una sola función, pero debe tener cuidado de no modificar los diccionarios de ninguna de las fuentes, y la forma más segura de evitarlo es hacer una copia al asignar valores. Como las claves deben ser hashable y, por lo tanto, generalmente son inmutables, no tiene sentido copiarlas:

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

Uso:

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

Proponer contingencias para otros tipos de valores está mucho más allá del alcance de esta pregunta, por lo que lo señalaré en mi respuesta a la pregunta canónica sobre una "fusión de diccionarios de diccionarios" .

Ad-hocs menos eficaces pero correctos

Estos enfoques tienen menos rendimiento, pero proporcionarán un comportamiento correcto. Tendrán mucho menos rendimiento que copyy updateo el nuevo desempaquetado porque iteran a través de cada par clave-valor en un nivel más alto de abstracción, pero respetan el orden de precedencia (los últimos diccionarios tienen precedencia)

También puede encadenar los diccionarios manualmente dentro de una comprensión de dictado :

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

o en Python 2.6 (y quizás ya en 2.4 cuando se introdujeron las expresiones del generador):

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

itertools.chainencadenará los iteradores sobre los pares clave-valor en el orden correcto:

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

Análisis de rendimiento

Solo voy a hacer el análisis de rendimiento de los usos que se sabe que se comportan correctamente. (Independiente para que pueda copiar y pegar usted mismo).

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

En 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

Recursos sobre diccionarios

En tu caso, lo que puedes hacer es:

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

Esto, como lo desee, colocará el dictado final zy hará que el valor de la clave bse anule correctamente por el yvalor del segundo dictamen ( ):

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

Si usa Python 2, incluso puede eliminar las list()llamadas. Para crear z:

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

Si usa Python versión 3.9.0a4 o superior, puede usar directamente:

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

Una alternativa:

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

Otra opción más concisa:

z = dict(x, **y)

Nota : esta se ha convertido en una respuesta popular, pero es importante señalar que si ytiene claves que no son cadenas, el hecho de que esto funcione es un abuso de un detalle de implementación de CPython, y no funciona en Python 3, o en PyPy, IronPython o Jython. Además, Guido no es un fan . Por lo tanto, no puedo recomendar esta técnica para código portátil de implementación cruzada o compatible con versiones posteriores, lo que realmente significa que debe evitarse por completo.

Probablemente esta no sea una respuesta popular, pero es casi seguro que no quieras hacer esto. Si desea una copia que sea una combinación, use copy (o deepcopy , según lo que desee) y luego actualice. Las dos líneas de código son mucho más legibles, más Pythonic, que la creación de una sola línea con .items() + .items(). Explícito es mejor que implícito.

Además, cuando usa .items() (anterior a Python 3.0), está creando una nueva lista que contiene los elementos del dict. Si sus diccionarios son grandes, entonces eso es una gran sobrecarga (dos listas grandes que se descartarán tan pronto como se cree el dict fusionado). update() puede funcionar de manera más eficiente, ya que puede ejecutar el segundo dictado elemento por elemento.

En términos de tiempo :

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

En mi opinión, la pequeña desaceleración entre los dos primeros vale la pena por la legibilidad. Además, los argumentos de palabras clave para la creación de diccionarios solo se agregaron en Python 2.3, mientras que copy() y update() funcionarán en versiones anteriores.

En una respuesta de seguimiento, preguntó sobre el rendimiento relativo de estas dos alternativas:

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

En mi máquina, al menos (una x86_64 bastante ordinaria que ejecuta Python 2.5.2), la alternativa z2no solo es más corta y simple, sino también significativamente más rápida. Puedes verificar esto por ti mismo usando el timeitmódulo que viene con Python.

Ejemplo 1: diccionarios idénticos que asignan 20 enteros consecutivos a sí mismos:

% 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

z2gana por un factor de 3,5 más o menos. Diferentes diccionarios parecen arrojar resultados bastante diferentes, pero z2siempre parecen salir adelante. (Si obtiene resultados inconsistentes para la misma prueba, intente pasar -rcon un número mayor que el predeterminado 3).

Ejemplo 2: diccionarios no superpuestos que asignan 252 cadenas cortas a números enteros y viceversa:

% 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

z2gana por un factor de 10. ¡Esa es una gran victoria en mi opinión!

Después de comparar esos dos, me pregunté si z1el bajo rendimiento de podría atribuirse a la sobrecarga de construir las dos listas de elementos, lo que a su vez me llevó a preguntarme si esta variación podría funcionar mejor:

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

Algunas pruebas rápidas, por ejemplo

% 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

me lleva a concluir que z3es un poco más rápido que z1, pero no tan rápido como z2. Definitivamente no vale la pena todo el tipeo extra.

A esta discusión todavía le falta algo importante, que es una comparación de rendimiento de estas alternativas con la forma "obvia" de fusionar dos listas: usar el updatemétodo. Para tratar de mantener las cosas en pie de igualdad con las expresiones, ninguna de las cuales modifica x o y, voy a hacer una copia de x en lugar de modificarla en el lugar, de la siguiente manera:

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

Un resultado típico:

% 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

En otras palabras, z0y z2parecen tener un rendimiento esencialmente idéntico. ¿Crees que esto podría ser una coincidencia? Yo no....

De hecho, iría tan lejos como para afirmar que es imposible que el código puro de Python funcione mejor que esto. Y si puede hacerlo significativamente mejor en un módulo de extensión de C, me imagino que la gente de Python podría estar interesada en incorporar su código (o una variación de su enfoque) en el núcleo de Python. Python se usa dicten muchos lugares; optimizar sus operaciones es un gran problema.

También podrías escribir esto como

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

como lo hace Tony, pero (como era de esperar) la diferencia en la notación resulta no tener ningún efecto medible en el rendimiento. Usa lo que te parezca correcto. Por supuesto, tiene toda la razón al señalar que la versión de dos declaraciones es mucho más fácil de entender.

En Python 3.0 y versiones posteriores , puede usar collections.ChainMapque agrupa varios dictados u otras asignaciones para crear una vista única y actualizable:

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

Actualización para Python 3.5 y versiones posteriores : puede usar el empaquetado y desempaquetado del diccionario extendido PEP 448 . Esto es rápido y fácil:

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

Actualización para Python 3.9 y versiones posteriores : puede usar el operador de unión PEP 584 :

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

Quería algo similar, pero con la capacidad de especificar cómo se fusionaron los valores en las claves duplicadas, así que lo eliminé (pero no lo probé en profundidad). Obviamente, esta no es una expresión única, sino una llamada de función única.

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

Actualización recursiva/profunda de un dictado

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

Demostración:

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

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

print deepupdate(pluto_original, pluto_update)

Salidas:

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

Gracias rednaw por las ediciones.

Python 3.5 (PEP 448) permite una mejor opción de sintaxis:

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

O incluso

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

En Python 3.9 también usas | y |= con el siguiente ejemplo de PEP 584

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

La mejor versión que podría pensar sin usar la copia sería:

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

Es más rápido que , dict(x.items() + y.items())pero no tan rápido como n = copy(a); n.update(b), al menos en CPython. Esta versión también funciona en Python 3 si cambia iteritems()a items(), lo que hace automáticamente la herramienta 2to3.

Personalmente, me gusta más esta versión porque describe bastante bien lo que quiero en una sola sintaxis funcional. El único problema menor es que no hace completamente obvio que los valores de y tengan prioridad sobre los valores de x, pero no creo que sea difícil darse cuenta de eso.

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

Para los elementos con claves en ambos diccionarios ('b'), puede controlar cuál termina en la salida colocándolo en último lugar.

Si bien la pregunta ya se ha respondido varias veces, esta solución simple al problema aún no se ha incluido en la lista.

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

Es tan rápido como z0 y el malvado z2 mencionado anteriormente, pero fácil de entender y cambiar.

def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)

Entre respuestas tan sombrías y dudosas, este brillante ejemplo es la única forma buena de fusionar dictados en Python, ¡respaldado por el propio dictador vitalicio Guido van Rossum ! Alguien más sugirió la mitad de esto, pero no lo puso en una función.

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

da:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}

Si crees que las lambdas son malas, no sigas leyendo. Según lo solicitado, puede escribir la solución rápida y eficiente en memoria con una expresión:

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}

Como se sugirió anteriormente, usar dos líneas o escribir una función es probablemente una mejor manera de hacerlo.

Ser pitónico. Usa una comprensión :

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

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

En python3, el itemsmétodo ya no devuelve una lista , sino una vista , que actúa como un conjunto. En este caso, deberá tomar la unión establecida, ya que la concatenación con +no funcionará:

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

Para un comportamiento similar a python3 en la versión 2.7, el viewitemsmétodo debería funcionar en lugar de items:

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

Prefiero esta notación de todos modos, ya que parece más natural pensar en ella como una operación de unión de conjuntos en lugar de una concatenación (como muestra el título).

Editar:

Un par de puntos más para python 3. Primero, tenga en cuenta que el dict(x, **y)truco no funcionará en python 3 a menos que las claves ysean cadenas.

Además, la respuesta de Chainmap de Raymond Hettinger es bastante elegante, ya que puede tomar una cantidad arbitraria de dictados como argumentos, pero a partir de los documentos parece que busca secuencialmente una lista de todos los dictados para cada búsqueda:

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

Esto puede ralentizarlo si tiene muchas búsquedas en su aplicación:

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

Entonces, aproximadamente un orden de magnitud más lento para las búsquedas. Soy fanático de Chainmap, pero parece menos práctico donde puede haber muchas búsquedas.

dos diccionarios

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

n diccionarios

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

sumtiene mal rendimiento. Consulte https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

Solución simple usando itertools que preserva el orden (los últimos dictados tienen prioridad)

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

Y su uso:

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

Comparé lo sugerido con perfplot y descubrí que el buen viejo

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

es la solución más rápida junto con la nueva (Python 3.9+)

x | y

ingrese la descripción de la imagen aquí


Código para reproducir la trama:

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


b = perfplot.bench(
    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(18)],
    xlabel="len(x), len(y)",
    equality_check=None,
)
b.save("out.png")
b.show()

Abuso que conduce a una solución de una expresión para la respuesta de Matthew :

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

Dijiste que querías una expresión, así que abusé lambdade vincular un nombre y tuplas para anular el límite de una expresión de lambda. Siéntete libre de encogerte.

Por supuesto, también podría hacer esto si no le importa copiarlo:

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

A pesar de que las respuestas fueron buenas para este diccionario superficial , ninguno de los métodos definidos aquí realiza una fusión profunda del diccionario.

A continuación se muestran algunos ejemplos:

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

Uno esperaría un resultado de algo como esto:

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

En cambio, obtenemos esto:

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

La entrada 'uno' debería haber tenido 'profundidad_2' y 'extra' como elementos dentro de su diccionario si realmente fuera una combinación.

Usar cadena también, no funciona:

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

Resultados en:

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

La fusión profunda que dio rcwesick también crea el mismo resultado.

Sí, funcionará para fusionar los diccionarios de muestra, pero ninguno de ellos es un mecanismo genérico para fusionar. Actualizaré esto más tarde una vez que escriba un método que haga una fusión verdadera.

Si no te importa mutar x,

x.update(y) or x

Simple, legible, eficaz. Sabes que siempre update() devuelve None, que es un valor falso. Entonces, la expresión anterior siempre se evaluará como x, después de actualizarla.

La mayoría de los métodos de mutación en la biblioteca estándar (como .update()) regresan Nonepor convención, por lo que este tipo de patrón también funcionará en ellos. Sin embargo, si está utilizando una subclase dict o algún otro método que no sigue esta convención, entonces orpuede devolver su operando izquierdo, que puede no ser lo que desea. En su lugar, puede usar una pantalla de tupla y un índice, que funciona independientemente de lo que evalúe el primer elemento (aunque no es tan bonito):

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

Si aún no tiene xuna variable, puede usar lambdapara hacer un local sin usar una instrucción de asignación. Esto equivale a usar lambdacomo una expresión let , que es una técnica común en los lenguajes funcionales, pero tal vez no sea pitónica.

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

Aunque no es tan diferente del siguiente uso del nuevo operador walrus (solo Python 3.8+),

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

especialmente si usa un argumento predeterminado:

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

Si desea una copia, el estilo PEP 584x | y es el más Pythonic en 3.9+. Si debe admitir versiones anteriores, el estilo PEP 448{**x, **y} es más fácil para 3.5+. Pero si eso no está disponible en su versión de Python (incluso más antigua), el patrón de expresión let también funciona aquí.

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

(Eso es, por supuesto, casi equivalente a (z := x.copy()).update(y) or z, pero si su versión de Python es lo suficientemente nueva para eso, entonces el estilo PEP 448 estará disponible).

Nuevo en Python 3.9: use el operador de unión (|) para fusionardicts similares asets:

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

Para las claves coincidentes, la derecha dicttiene prioridad .

Esto también funciona para |=modificar un dictlugar:

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

Es tan tonto que .updateno devuelve nada.
Solo uso una función de ayuda simple para resolver el problema:

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

Ejemplos:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy

(Solo para Python2.7*; existen soluciones más sencillas para Python3*.)

Si no es reacio a importar un módulo de biblioteca estándar, puede hacerlo

from functools import reduce

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

(El or abit en el lambdaes necesario porque dict.updatesiempre regresa Noneen caso de éxito).

Basándome en ideas aquí y en otros lugares, he comprendido una función:

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

Uso (probado en 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})

Podrías usar una lambda en su lugar.

El problema que tengo con las soluciones enumeradas hasta la fecha es que, en el diccionario fusionado, el valor de la clave "b" es 10 pero, a mi manera de pensar, debería ser 12. En ese sentido, presento lo siguiente:

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

Resultados:

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}

Habrá una nueva opción cuando se lance Python 3.8 ( programado para el 20 de octubre de 2019 ), gracias a PEP 572: Expresiones de asignación . El nuevo operador de expresión de asignación :=le permite asignar el resultado de copyy aún usarlo para llamar update, dejando el código combinado como una sola expresión, en lugar de dos declaraciones, cambiando:

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

para:

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

mientras se comportan de manera idéntica en todos los sentidos. Si también debe devolver el resultado dict(solicitó una expresión que devolviera el dict; lo anterior crea y asigna a newdict, pero no lo devuelve, por lo que no podría usarlo para pasar un argumento a una función tal cual, a la myfunc((newdict := dict1.copy()).update(dict2))) , luego solo agregue or newdicthasta el final (ya que updatedevuelve None, que es falso, luego evaluará y devolverá newdictcomo resultado de la expresión):

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

Advertencia importante: en general, desaconsejaría este enfoque a favor de:

newdict = {**dict1, **dict2}

El enfoque de desempaquetado es más claro (para cualquiera que sepa sobre el desempaquetado generalizado en primer lugar, lo cual debería ), no requiere un nombre para el resultado en absoluto (por lo que es mucho más conciso cuando se construye un temporal que se pasa inmediatamente a un función o incluido en un list/ tupleliteral o similar), y es casi seguro que también es más rápido, siendo (en CPython) aproximadamente equivalente a:

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

pero hecho en la capa C, utilizando la dictAPI concreta, por lo que no se involucra la búsqueda/enlace de métodos dinámicos ni la sobrecarga de envío de llamadas a funciones (donde (newdict := dict1.copy()).update(dict2)es inevitablemente idéntico al comportamiento original de dos líneas, realizando el trabajo en pasos discretos, con búsqueda dinámica /enlace/invocación de métodos.

También es más extensible, ya que la combinación de tres dicts es obvia:

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

donde el uso de expresiones de asignación no escalará así; lo más cercano que podrías conseguir sería:

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

o sin la tupla temporal de Nones, pero con pruebas de veracidad de cada Noneresultado:

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

cualquiera de los cuales es obviamente mucho más feo e incluye más ineficiencias (ya sea un desperdicio temporal tuplede Nones para la separación por coma, o una prueba de veracidad sin sentido del retorno de cada uno updatepara la Noneseparación or).

La única ventaja real del enfoque de expresión de asignación ocurre si:

  1. Tiene un código genérico que necesita manejar tanto sets como dicts (ambos admiten copyy update, por lo que el código funciona más o menos como lo esperaría)
  2. Espera recibir objetos similares a dictados arbitrarios , no solo dicten sí mismo, y debe conservar el tipo y la semántica del lado izquierdo (en lugar de terminar con un simple dict). Si bien myspecialdict({**speciala, **specialb})podría funcionar, implicaría un temporal adicional dict, y si myspecialdicttiene características que simplemente dictno se pueden conservar (por ejemplo , los dicts regulares ahora conservan el orden en función de la primera aparición de una clave y el valor en función de la última aparición de una clave; es posible que desee uno que preserva el orden basado en el últimoaparición de una clave, por lo que actualizar un valor también lo mueve al final), entonces la semántica sería incorrecta. Dado que la versión de la expresión de asignación utiliza los métodos con nombre (que presumiblemente están sobrecargados para comportarse adecuadamente), nunca crea un dict(a menos dict1que ya fuera un dict), preservando el tipo original (y la semántica del tipo original), todo mientras evita los temporales.
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))

Esto debería solucionar tu problema.