Python „przedłużyć” dla słownika


462

Jaki jest najlepszy sposób na rozszerzenie słownika o inny? Na przykład:

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

Szukam dowolnej operacji, aby uzyskać forpętlę omijania :

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

Chcę zrobić coś takiego:

a.extend(b)  # This does not work

25
Wiedziałem o listach [], więc przypuszczam, że może być praca dla innych, a nie rozszerzanie ;-)
FerranB

Odpowiedzi:


694

6
Po przeczytaniu dokumentacji zrozumiecie, dlaczego istnieje „aktualizacja”, ale nie „przedłużenie”.
georg

58
pamiętaj, że update () bezpośrednio modyfikuje dykt i zwraca None.
e18r

5
Ale co jeśli chcesz rozszerzyć dyktat o wartości, które nie zostały jeszcze zdefiniowane (tj. Nie nadpisują istniejących wartości)? Na przykład zaktualizować dykt za {"a":2, "b":3}pomocą dykta, {"b":4, "c":5}aby dyktować {"a":2, "b":3,"c":5}? Oczywiście można to wykorzystać update(), przenosząc różne rzeczy, ale byłoby lepiej, gdyby można było to osiągnąć tylko w jednej linii ...
Nearoo

17
@Nearoo - po prostu zaktualizuj w drugą stronę; zamiast x.update (y) [który nadpisania wartości x z y] użyć y.update (x) [który nadpisuje wartości z y] x i y, jak używanie wybranego dict dalszych operacji
jonathanl

pamiętaj, że updatepo cichu nadpisuje istniejące wpisy. Oznacza to, że wszelkie wartości bzastępują wartości adla nakładających się kluczy.
CGFoX

186

Piękny klejnot w tym zamkniętym pytaniu :

„Sposób onelinera”, który nie zmienia żadnego z dykt wejściowych, jest

basket = dict(basket_one, **basket_two)

Dowiedzieć się, co **basket_two(z **) oznaczają tutaj .

W przypadku konfliktu przedmioty z basket_twozastąpią te z basket_one. W miarę, jak powstają jedno-linijki, jest to dość czytelne i przejrzyste, a ja nie mam żadnych przeciwwskazań do używania go za każdym razem, gdy przydaje się dyktando, które jest mieszanką dwóch innych (każdy czytelnik, który ma problemy ze zrozumieniem, w rzeczywistości będzie bardzo dobrze obsługiwany przez sposób, w jaki zachęca go to do nauki dicti **formy ;-). Na przykład wykorzystuje takie jak:

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

są dość częstymi zdarzeniami w moim kodzie.

Pierwotnie przesłane przez Alexa Martelli

Uwaga: W Pythonie 3 zadziała to tylko wtedy, gdy każdy klucz w koszyku_dwie jest a string.


3
Dokumentacja dla dictjest łatwa do znalezienia, **a nieco trudniejsza (słowo kluczowe to kwargs ). Oto ładne wyjaśnienie: saltycrane.com/blog/2008/01/…
johndodo

4
może to zostać wykorzystane do wygenerowania drugiej zmiennej za pomocą pojedynczego polecenia, natomiast, basket_one.update(<dict>)jak sama nazwa mówi, aktualizuje istniejący słownik (lub klonowany).
furins

2
Zauważ, że w Pythonie 3 nazwy argumentów, a więc klucze **anotherdict, muszą być łańcuchami.
Petr Viktorin

Dzięki @johndodo - Włączyłem twoje sugestie do postu.
Tom Leys

1
Fajna funkcjonalna alternatywa dla przyjętej odpowiedzi. Takie podejście jest pożądane, jeśli chcesz bezpośrednio użyć nowo połączonego nagrania. (zobacz także komentarz @ e18r do zaakceptowanej odpowiedzi).
chinnychinchin

45

Czy próbowałeś używać zrozumienia słownika z mapowaniem słownika:

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

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

Innym sposobem jest użycie dict (iterable, ** kwarg)

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

W Pythonie 3.9 możesz dodać dwa dykty za pomocą union | operator

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

5
Do Twojej wiadomości: nie jest to poprawna składnia w Pythonie 2.7
Asav Patel,

2
Ta składnia jest dość nowa (Python 3.5)
pianoJames

24
a.update(b)

Dodaje klucze i wartości od b do a , zastępując je, jeśli istnieje już wartość klucza.


17

Jak wspomnieli inni, a.update(b)dla niektórych dykt ai bosiągną wynik, o który prosiłeś w swoim pytaniu. Chcę jednak podkreślić, że wiele razy widziałem extendmetodę mapowania / zestaw przedmiotów, które pragną w składni a.extend(b), a„s wartości nie powinny być zastąpione przez b” s wartości. a.update(b)nadpisuje awartości, więc nie jest to dobry wybór extend.

Zauważ, że niektóre języki wywołują tę metodę defaultslub inject, jak można ją traktować, jako sposób na wstrzyknięcie wartości b (które mogą być zestawem wartości domyślnych) do słownika bez nadpisywania wartości, które już mogą istnieć.

Oczywiście możesz zauważyć prostą notatkę, która a.extend(b)jest prawie taka sama jak b.update(a); a=b. Aby usunąć zadanie, możesz to zrobić w następujący sposób:

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)

Dzięki Tomowi Leysowi za ten sprytny pomysł wykorzystujący konstruktor bez efektów ubocznych dictdla extend.


1

Możesz także użyć kolekcji Pythona. Chainmap, która została wprowadzona w Pythonie 3.3.

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

Ma to kilka możliwych zalet, w zależności od przypadku użycia. Są one wyjaśnione bardziej szczegółowo tutaj , ale dam krótki przegląd:

  • Mapa łańcuchowa używa tylko widoków słowników, więc żadne dane nie są kopiowane. Powoduje to szybsze tworzenie łańcuchów (ale wolniejsze wyszukiwanie)
  • W rzeczywistości żadne klucze nie są nadpisywane, więc w razie potrzeby wiesz, czy dane pochodzą z a, czy b.

To głównie sprawia, że ​​jest użyteczny w takich rzeczach, jak słowniki konfiguracji.


0

Jeśli potrzebujesz go jako klasy , możesz go rozszerzyć za pomocą dict i użyć metody aktualizacji :

Class a(dict):
  # some stuff
  self.update(b)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.