Python "estende" per un dizionario


464

Qual è il modo migliore per estendere un dizionario con un altro? Per esempio:

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

Sto cercando qualsiasi operazione per ottenere questo forcircuito da evitare :

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

Vorrei fare qualcosa del tipo:

a.extend(b)  # This does not work

25
Conoscevo gli elenchi [], quindi suppongo che potrebbe funzionare per altri, non strano ;-)
FerranB,

Risposte:


696

6
Dopo aver letto i documenti si capirà perché c'è un "aggiornamento" ma non un "prolungamento".
Georg,

58
tenere presente che update () modifica direttamente il dict e restituisce None.
e18r

5
Ma cosa succede se si desidera estendere il dict solo con valori che non sono già definiti (ovvero non sovrascrivere i valori esistenti)? Ad esempio, aggiornare un dict {"a":2, "b":3}con dict {"b":4, "c":5}a dict {"a":2, "b":3,"c":5}? Ovviamente è possibile utilizzarlo update()spostando alcune cose in giro, ma sarebbe più bello se potesse essere realizzato in una sola riga ...
Nearoo,

17
@Nearoo - aggiorna semplicemente il contrario; invece di x.update (y) [che sovrascriverebbe x valori con y], usa y.update (x) [che sovrascrive y valori con x] e usa y come dict scelto per ulteriori operazioni
jonathanl

tenere presente che updatesovrascrive silenziosamente le voci esistenti. Vale a dire, tutti i valori in bsovrascrivono quelli in aper le chiavi sovrapposte.
CGFoX

186

Un gioiello bellissimo in questa domanda chiusa :

Il "modo oneliner", che non modifica nessuno dei due input, è

basket = dict(basket_one, **basket_two)

Scopri cosa significa **basket_two(il **) qui .

In caso di conflitto, gli articoli di basket_twosostituiranno quelli di basket_one. In linea di principio, questo è piuttosto leggibile e trasparente, e non ho alcun obbligo di usarlo ogni volta che un dict che è un mix di due altri è utile (qualsiasi lettore che ha difficoltà a capirlo sarà in effetti molto ben servito da il modo in cui questo lo spinge a conoscere dicte la **forma ;-). Quindi, ad esempio, usa come:

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

sono occorrenze ragionevolmente frequenti nel mio codice.

Originariamente inviato da Alex Martelli

Nota: in Python 3, funzionerà solo se ogni chiave in basket_two è a string.


3
La documentazione per dictè facile da trovare mentre **è un po 'più complicata (la parola chiave è kwargs ). Ecco una bella spiegazione: saltycrane.com/blog/2008/01/…
johndodo

4
questo può essere usato per generare una seconda variabile con un singolo comando, mentre basket_one.update(<dict>)come dice il nome, aggiorna un dizionario esistente (o clonato).
furins

2
Nota che in Python 3, i nomi degli argomenti, e quindi le chiavi di **anotherdict, devono essere stringhe.
Petr Viktorin,

Grazie @johndodo - Ho integrato i tuoi suggerimenti nel post.
Tom Leys,

1
Una bella alternativa funzionale alla risposta accettata. Questo approccio è auspicabile se è necessario utilizzare direttamente il dict appena combinato. (vedi anche il commento di @ e18r sulla risposta accettata).
chinnychinchin

45

Hai provato a usare la comprensione del dizionario con la mappatura del dizionario:

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

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

Un altro modo di fare è usare dict (iterabile, ** kwarg)

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

In Python 3.9 puoi aggiungere due dict usando union | operatore

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

5
A proposito: questa non è una sintassi valida in Python 2.7
Asav Patel,

2
Questa sintassi è abbastanza nuova (Python 3.5)
pianoJames,

24
a.update(b)

Aggiungerà chiavi e valori da b a a , sovrascrivendo se esiste già un valore per una chiave.


17

Come altri hanno già detto, a.update(b)per alcuni dadi ae braggiungerà il risultato che hai chiesto nella tua domanda. Tuttavia, voglio far notare che molte volte ho visto il extendmodo di mappatura / oggetti set desiderano che nella sintassi a.extend(b), a's valori non devono essere sovrascritti da b' s valori. a.update(b)sovrascrive ai valori, e quindi non è una buona scelta per extend.

Si noti che alcune lingue chiamano questo metodo defaultso inject, come si può pensare come un modo per iniettare i valori di b (che potrebbero essere un insieme di valori predefiniti) in un dizionario senza sovrascrivere valori che potrebbero già esistere.

Certo, potresti semplicemente notare che a.extend(b)è quasi lo stesso di b.update(a); a=b. Per rimuovere il compito, puoi farlo in questo modo:

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)

Grazie a Tom Leys per quell'idea intelligente che usa un dictcostruttore senza effetti collaterali per extend.


1

Puoi anche usare le raccolte di python.Chainmap che è stato introdotto in python 3.3.

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

Ciò presenta alcuni possibili vantaggi, a seconda del caso d'uso. Sono spiegati in modo più dettagliato qui , ma darò una breve panoramica:

  • Una chainmap utilizza solo le viste dei dizionari, quindi nessun dato viene effettivamente copiato. Ciò comporta un concatenamento più rapido (ma una ricerca più lenta)
  • Nessuna chiave viene effettivamente sovrascritta, quindi, se necessario, sai se i dati provengono da a o b.

Ciò lo rende principalmente utile per cose come i dizionari di configurazione.


0

Se ne hai bisogno come classe , puoi estenderlo con dict e utilizzare il metodo di aggiornamento :

Class a(dict):
  # some stuff
  self.update(b)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.