Python "extender" para un diccionario


464

¿Cuál es la mejor manera de extender un diccionario con otro? Por ejemplo:

>>> a = { "a" : 1, "b" : 2 }
>>> b = { "c" : 3, "d" : 4 }
>>> a
{'a': 1, 'b': 2}
>>> b
{'c': 3, 'd': 4}

Estoy buscando cualquier operación para obtener este forbucle de evitación :

{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }

Deseo hacer algo como:

a.extend(b)  # This does not work

25
Lo sabía para las listas [], entonces supongo que puede ser trabajo para otros, no extraños ;-)
FerranB

Respuestas:


696

66
Después de leer los documentos, uno comprenderá por qué hay una "actualización" pero no una "extensión".
georg

58
tenga en cuenta que update () modifica directamente el dict y devuelve None.
e18r

55
Pero, ¿qué sucede si solo desea extender el dict con valores que no están definidos ya (es decir, no sobrescribir los valores existentes)? Por ejemplo, ¿actualizar un dict {"a":2, "b":3}con dict {"b":4, "c":5}a dict {"a":2, "b":3,"c":5}? Por supuesto, es posible usarlo update()moviendo algunas cosas, pero sería mejor si se pudiera lograr en una sola línea ...
Nearoo

17
@Nearoo: simplemente actualice de la manera opuesta; en lugar de x.update (y) [que sobrescribiría los valores de x con y], use y.update (x) [que sobrescribe los valores de y con x] y use y como su dict elegido para otras operaciones
jonathanl

tenga en cuenta que updatesobrescribe silenciosamente las entradas existentes. Es decir, cualquier valor en bsobrescribir aquellos en alas teclas superpuestas.
CGFoX

186

Una hermosa joya en esta pregunta cerrada :

La "forma de línea", sin alterar ninguno de los dictados de entrada, es

basket = dict(basket_one, **basket_two)

Aprende lo que **basket_two(el **) significa aquí .

En caso de conflicto, los elementos de basket_twoanularán los de basket_one. A medida que avanza una frase, esto es bastante legible y transparente, y no tengo reparo en usarlo cada vez que un dict que es una mezcla de otros dos es útil (cualquier lector que tenga problemas para entenderlo, de hecho, será muy bien servido por la forma en que esto lo impulsa a aprender dicty la **forma ;-). Entonces, por ejemplo, usa como:

x = mungesomedict(dict(adict, **anotherdict))

son ocurrencias razonablemente frecuentes en mi código.

Originalmente presentado por Alex Martelli

Nota: En Python 3, esto solo funcionará si cada clave en basket_two es a string.


3
La documentación para dictes fácil de encontrar mientras que **es un poco más complicada (la palabra clave es kwargs ). Aquí hay una buena explicación: saltycrane.com/blog/2008/01/…
johndodo

44
esto puede usarse para generar una segunda variable con un solo comando, mientras que, basket_one.update(<dict>)como su nombre lo indica, actualiza un diccionario existente (o uno clonado).
furins

2
Tenga en cuenta que en Python 3, los nombres de los argumentos y, por lo tanto, las claves de **anotherdict, deben ser cadenas.
Petr Viktorin

Gracias @johndodo: he integrado tus sugerencias en la publicación.
Tom Leys

1
Una buena alternativa funcional a la respuesta aceptada. Este enfoque es deseable si necesita utilizar directamente el dict recientemente combinado. (también vea el comentario de @ e18r sobre la respuesta aceptada).
chinnychinchin

45

¿Has intentado usar la comprensión del diccionario con el mapeo del diccionario?

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

c = {**a, **b}
# c = {"a": 1, "b": 2, "c": 3, "d": 4}

Otra forma de hacerlo es mediante el uso de dict (iterable, ** kwarg)

c = dict(a, **b)
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

En Python 3.9 puede agregar dos dict usando union | operador

# use the merging operator |
c = a | b
# c = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

55
FYI: esta no es una sintaxis válida en Python 2.7
Asav Patel

2
Esta sintaxis es bastante nueva (Python 3.5)
pianoJames

24
a.update(b)

Agregará claves y valores de b a a , sobrescribiendo si ya hay un valor para una clave.


17

Como otros han mencionado, a.update(b)para algunos dictados ay blogrará el resultado que ha pedido en su pregunta. Sin embargo, quiero señalar que muchas veces he visto que el extendmétodo de mapear / establecer objetos desea que en la sintaxis a.extend(b), alos valores de NO se sobrescriban con blos valores de. a.update(b)sobrescribe alos valores, por lo que no es una buena opción paraextend .

Tenga en cuenta que algunos idiomas llaman a este método defaultsoinject , ya que puede considerarse como una forma de inyectar los valores de b (que podrían ser un conjunto de valores predeterminados) en un diccionario sin sobrescribir los valores que ya podrían existir.

Por supuesto, podrías notar que a.extend(b)es casi lo mismo que b.update(a); a=b. Para eliminar la asignación, puede hacerlo así:

def extend(a,b):
    """Create a new dictionary with a's properties extended by b,
    without overwriting.

    >>> extend({'a':1,'b':2},{'b':3,'c':4})
    {'a': 1, 'c': 4, 'b': 2}
    """
    return dict(b,**a)

Gracias a Tom Leys por esa idea inteligente usando un dictconstructor sin efectos secundarios extend.


1

También puede usar las colecciones de Python. Chainmap que se introdujo en Python 3.3.

from collections import Chainmap
c = Chainmap(a, b)
c['a'] # returns 1

Esto tiene algunas ventajas posibles, dependiendo de su caso de uso. Se explican con más detalle aquí , pero voy a dar una breve descripción:

  • Un mapa de cadena solo usa vistas de los diccionarios, por lo que no se copian datos. Esto da como resultado un encadenamiento más rápido (pero una búsqueda más lenta)
  • En realidad, no se sobrescriben las claves, por lo que, si es necesario, sabrá si los datos provienen de aob.

Esto lo hace principalmente útil para cosas como diccionarios de configuración.


0

En caso de que lo necesite como clase , puede extenderlo con dict y usar el método de actualización :

Class a(dict):
  # some stuff
  self.update(b)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.