Jak połączyć dwa słowniki w jedno wyrażenie w Pythonie (biorąc związek słowników)?

Mam dwa słowniki Pythona i chcę napisać jedno wyrażenie, które zwróci te dwa słowniki, połączone (tzn. biorąc Unię). Metoda update() byłaby tym, czego potrzebuję, jeśli zwróci wynik zamiast zmodyfikować słownik na miejscu.

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

Jak mogę uzyskać ten końcowy słownik scalony w z, a nie x?

(żeby było wyjątkowo jasne, ostatni-wygrywa obsługę konfliktu dict.update() jest tym, czego również Szukam.)

Author: Charlie Parker, 2008-09-02

30 answers

Jak połączyć dwa słowniki Pythona w jedno wyrażenie?

Dla słowników x i y, z staje się płytko scalonym słownikiem z wartościami z y zastępującymi wartości z x.

  • W Pythonie 3.9.0 lub nowszym (wydany 17 października 2020): PEP-584, omówione tutaj , został zaimplementowany i zapewnia najprostszą metodę:

    z = x | y          # NOTE: 3.9+ ONLY
    
  • W Pythonie 3.5 lub większy:

    z = {**x, **y}
    
  • W Pythonie 2 (lub 3.4 lub niższym) napisz funkcję:

    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
    

    A teraz:

    z = merge_two_dicts(x, y)
    

Wyjaśnienie

Powiedzmy, że masz dwa słowniki i chcesz połączyć je w Nowy dict bez zmiany oryginalnych słowników:]}
x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}

Pożądanym rezultatem jest uzyskanie nowego słownika (z) z wartościami scalonymi, a wartości drugiego słownika zastępują wartości z pierwszego.

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

Nowa składnia tego, proponowany w PEP 448 i dostępny od Pythona 3.5 , jest

z = {**x, **y}

I rzeczywiście jest to jedno wyrażenie.

Zauważ, że możemy również połączyć się z zapisem dosłownym:

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

A teraz:

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

Jest teraz pokazany jako zaimplementowany w harmonogram wydania dla 3.5, PEP 478, a teraz trafił do Co nowego w dokumencie Python 3.5 .

Jednakże, ponieważ wiele organizacji nadal pracuje nad Pythonem 2, możesz chcę to zrobić w sposób wstecznie zgodny. W Pythonie 3.0 i Pythonie 3.0-3.4 można to zrobić w dwuetapowy sposób:

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

W obu podejściach, y będzie druga, a jego wartości zastąpią wartości x, więc 'b' wskaże 3 w naszym ostatecznym wyniku.

Jeszcze nie na Pythonie 3.5, ale chcesz pojedyncze wyrażenie

Jeśli nie jesteś jeszcze na Pythonie 3.5 lub potrzebujesz napisać wstecznie zgodny kod, a chcesz to w pojedyncze wyrażenie , najbardziej wydajne, podczas gdy poprawne podejście jest umieszczenie go w funkcji:

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

I wtedy masz jedno wyrażenie:

z = merge_two_dicts(x, y)

Można również utworzyć funkcję scalającą niezdefiniowaną liczbę słowników, od zera do bardzo dużej liczby:

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

Ta funkcja będzie działać w Pythonie 2 i 3 dla wszystkich słowników. np. podane słowniki a do g:

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

I pary klucz-wartość w g będą miały pierwszeństwo ponad słownikami a do f, i tak dalej.

Krytyka innych odpowiedzi

Nie używaj tego, co widzisz w wcześniej zaakceptowanej odpowiedzi:

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

W Pythonie 2, tworzysz dwie listy w pamięci dla każdego dict, tworzysz trzecią listę w pamięci o długości równej długości dwóch pierwszych razem złożonych, a następnie odrzucasz wszystkie trzy listy, aby utworzyć dict. w Pythonie 3, to się nie powiedzie ponieważ dodajesz dwa dict_items obiekty razem, a nie dwie listy -

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

I musiałbyś jawnie utworzyć je jako listy, np. z = dict(list(x.items()) + list(y.items())). Jest to strata zasobów i mocy obliczeniowej.

Podobnie, użycie Unii items() w Pythonie 3 (viewitems() w Pythonie 2.7) również nie powiedzie się, gdy wartości są obiektami niehaszowalnymi (np. listami). Nawet jeśli twoje wartości są hashowalne, ponieważ zestawy nie są semantycznie uporządkowane, zachowanie jest niezdefiniowane w odniesieniu do pierwszeństwa. Więc nie rób tego:

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

Ten przykład pokazuje, co się dzieje, gdy wartości są niehaszowalne:

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

Oto przykład, w którym y powinno mieć pierwszeństwo, ale zamiast tego wartość z x jest zachowana ze względu na arbitralną kolejność zbiorów:

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

Kolejny hack, którego nie powinieneś używać:

z = dict(x, **y)

Używa konstruktora dict i jest bardzo szybki i efektywny pamięciowo (nawet nieco bardziej niż nasz dwuetapowy proces), ale jeśli nie wiesz dokładnie, co się tutaj dzieje (czyli drugi dict jest przekazywany jako słowo kluczowe argumenty do konstruktora dict), jest trudny do odczytania, nie jest to zamierzone użycie, a więc nie jest Pythoniczne.

Oto przykład użycia naprawionego w django .

Słowniki mają przyjmować klucze hashowalne (np. frozensets lub krotki), ale ta metoda zawodzi w Pythonie 3, gdy klucze nie są ciągami.

>>> c = dict(a, **b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings
Z listy dyskusyjnej[71]} Guido van Rossum, twórca języka, napisał: [66]}

Jestem dobrze z deklarowanie dict({}, **{1:3}) nielegalne, ponieważ przecież jest to nadużycie mechanizm**.

I

Widocznie dict(x, **y) chodzi jak "cool hack" dla " call X. update (y) I return x". Osobiście uważam to za bardziej podłe niż Super.

W 2007 roku, w ramach programu "Horyzont 2020", w ramach programu "Horyzont 2020" - programu ramowego w zakresie badań naukowych i innowacji (2014-2020), zrealizowano program "Horyzont 2020" - program ramowy w zakresie badań naukowych i innowacji (2014-2020), który obejmuje lata 2014-2020 i 2020-2020., np.:
dict(a=1, b=10, c=11)

Zamiast

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

Odpowiedź na komentarze

Wbrew temu, co mówi Guido, dict(x, **y) jest zgodne ze specyfikacją dict, która btw. działa zarówno dla Pythona 2 jak i 3. Fakt, że działa to tylko w przypadku kluczy łańcuchowych, jest bezpośrednią konsekwencją działania parametrów słów kluczowych, a nie skrótem dict. Użycie w tym miejscu operatora * * nie jest nadużyciem mechanizmu, w rzeczywistości * * został zaprojektowany właśnie po to, aby przekazać słowniki jako słowa kluczowe.

Ponownie, nie działa dla 3, gdy klucze nie są ciągami. Implicit calling contract polega na tym, że przestrzenie nazw przyjmują zwykłe słowniki, podczas gdy użytkownicy muszą przekazywać tylko argumenty słów kluczowych, które są ciągami znaków. Wszystkie inne wezwania go egzekwowały. dict złamał tę spójność w Pythonie 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}

Ta niespójność była zła ze względu na inne implementacje Pythona (Pypy, Jython, IronPython). W ten sposób został naprawiony w Pythonie 3, ponieważ użycie to może być łamaniem zmiana.

Oświadczam, że złośliwą niekompetencją jest celowe pisanie kodu, który działa tylko w jednej wersji języka lub który działa tylko z pewnymi arbitralnymi ograniczeniami.

Więcej komentarzy:

dict(x.items() + y.items()) jest nadal najbardziej czytelnym rozwiązaniem dla Pythona 2. Liczy się czytelność.

Moja odpowiedź: merge_two_dicts(x, y) wydaje mi się dużo jaśniejsza, jeśli zależy nam na czytelności. I nie jest kompatybilny z forward, ponieważ Python 2 jest coraz bardziej przestarzałe.

{**x, **y} wydaje się, że nie obsługuje zagnieżdżonych słowników. zawartość zagnieżdżonych kluczy jest po prostu nadpisywana, a nie scalana [...] Zostałem spalony przez te odpowiedzi, które nie łączą się rekurencyjnie i byłem zaskoczony, że nikt o tym nie wspomniał. W mojej interpretacji słowa "scalanie" odpowiedzi te opisują "aktualizowanie jednego dict z drugim", a nie scalanie.

Tak. Muszę odesłać Cię do pytania, które jest prośba o shallow merge of dwa słowniki, w których wartości pierwszego są nadpisywane przez drugie - w jednym wyrażeniu.

Zakładając dwa słowniki słowników, można je rekurencyjnie połączyć w jedną funkcję, ale należy uważać, aby nie modyfikować słowników z żadnego źródła, a najpewniejszym sposobem uniknięcia tego jest zrobienie kopii podczas przypisywania wartości. Ponieważ klucze muszą być hashable i są zazwyczaj niezmienne, jest nie ma sensu ich kopiować:

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

Użycie:

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

Wymyślanie możliwości dla innych typów wartości jest daleko poza zakresem tego pytania, więc wskażę ci moją odpowiedź na kanoniczne pytanie na "Słowniki słowników scalać" {71]}.

Mniej wydajny, ale poprawny Ad-hocs

Te podejścia są mniej wydajne, ale zapewnią poprawne zachowanie. Będą znacznie mniej niż copy i update czy nowe w przeciwieństwie do innych języków, w których klucz-wartość znajduje się na wyższym poziomie abstrakcji, nie jest on w stanie go rozpakować, ponieważ są one iterowane przez każdą parę klucz-wartość na wyższym poziomie abstrakcji, ale nie przestrzegają kolejności pierwszeństwa (Ostatnie słowniki mają pierwszeństwo)

Możesz również ręcznie łańcuchować słowniki wewnątrz rozumienia dict :
{k: v for d in dicts for k, v in d.items()} # iteritems in Python 2.7
W Pythonie 2.6 (i być może już w 2.4, kiedy wprowadzono wyrażenia generatora):
dict((k, v) for d in dicts for k, v in d.items()) # iteritems in Python 2

itertools.chain będzie łańcuchem iteratorów nad parami klucz-wartość w prawidłowym porządek:

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

Analiza Wydajności

Przeprowadzę tylko analizę wydajności zwyczaje znane z prawidłowego zachowania. (Samodzielne, dzięki czemu można kopiować i wklejać samodzielnie.)

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

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

Zasoby na słownikach

 6766
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-18 13:57:26

W Twoim przypadku, to co możesz zrobić to:

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

To, jak chcesz, umieści końcowy dict w z i sprawi, że wartość klucza b będzie odpowiednio przesłonięta przez drugą (y) wartość dict:

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

Jeśli używasz Pythona 2, możesz nawet usunąć wywołania list(). Aby utworzyć z:

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

Jeśli używasz Pythona w wersji 3.9. 0A4 lub nowszej, możesz użyć bezpośrednio:

x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = x | y
print(z)
{'a': 1, 'c': 11, 'b': 10}
 1673
Author: Thomas Vander Stichele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-30 21:08:09

Alternatywa:

z = x.copy()
z.update(y)
 667
Author: Matthew Schinckel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 13:00:46

Inna, bardziej zwięzła opcja:

z = dict(x, **y)

Uwaga: ta odpowiedź stała się popularną odpowiedzią, ale ważne jest, aby zwrócić uwagę, że jeśli y ma jakieś klucze nietekstowe, fakt, że to działa, jest nadużyciem szczegółów implementacji CPython i nie działa w Pythonie 3, ani w PyPy, IronPython lub Jython. Ponadto, Guido nie jest fanem . Więc nie mogę polecić tej techniki dla kompatybilnego lub cross-implementacji przenośnego kodu, co naprawdę oznacza, że powinno być unikał całkowicie.

 374
Author: Carl Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 06:43:24

Prawdopodobnie nie będzie to popularna odpowiedź, ale prawie na pewno nie chcesz tego robić. Jeśli chcesz mieć kopię scaloną, użyj copy (lub deepcopy , w zależności od tego, co chcesz), a następnie zaktualizuj. Dwie linie kodu są znacznie bardziej czytelne - bardziej Pythoniczne-niż tworzenie pojedynczej linii .items() + .pozycji(). Explicit jest lepszy niż implicit.

Dodatkowo, gdy używasz .items () (pre Python 3.0), tworzysz nową listę zawierającą elementy z dict. Jeśli Twoje słowniki są duże, to jest to sporo narzutu (dwie duże listy, które zostaną wyrzucone zaraz po utworzeniu scalonego dict). update() może działać wydajniej, ponieważ może działać przez drugi dict pozycja po pozycji.

W kategoriach czasu :

>>> 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 małe spowolnienie między dwoma pierwszymi jest tego warte ze względu na czytelność. Dodatkowo argumenty słów kluczowych do tworzenia słownika zostały dodane tylko w Pythonie 2.3, podczas gdy copy () i update() będzie działać w starszych wersjach.
 230
Author: Tony Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-05 23:56:02

W odpowiedzi uzupełniającej zapytałeś o względną wydajność tych dwóch alternatyw:

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

Na moim komputerze, przynajmniej (dość zwykły x86_64 z Pythonem 2.5.2), alternatywa z2 jest nie tylko krótsza i prostsza, ale także znacznie szybsza. Możesz to sprawdzić samodzielnie za pomocą modułu timeit dostarczanego z Pythonem.

Przykład 1: identyczne słowniki odwzorowujące 20 kolejnych liczb całkowitych do siebie:

% 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 wygrane przez współczynnik 3,5 mniej więcej. Różne słowniki wydają się dawać zupełnie inne wyniki, ale z2 zawsze wydają się wychodzić na wierzch. (Jeśli uzyskasz niespójne wyniki dla tego samego testu, spróbuj przejść -r z liczbą większą niż domyślna 3.)

Przykład 2: nie nakładające się słowniki odwzorowują 252 krótkie ciągi na liczby całkowite i odwrotnie:

% 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 wygrywa o współczynnik 10. To całkiem duża wygrana w mojej książce!

Po porównaniu tych dwóch, zastanawiałem się, czy Słaba wydajność może być przypisana do kosztów budowy dwóch list przedmiotów, co z kolei skłoniło mnie do zastanowienia się, czy ta odmiana może działać lepiej:]}

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

Kilka szybkich testów, np.

% 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

Doprowadzaj mnie do wniosku, że z3 jest nieco szybszy niż z1, ale nie prawie tak szybki jak z2. Zdecydowanie nie warto wszystkich dodatkowych wpisów.

W tej dyskusji wciąż brakuje czegoś ważnego, czyli porównania wydajności tych alternatyw z "oczywisty" sposób łączenia dwóch list: za pomocą metody update. Aby spróbować utrzymać rzeczy na równi z wyrażeniami, z których żadne nie modyfikuje x lub y, zrobię kopię x zamiast modyfikować go na miejscu, w następujący sposób: {]}

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

Typowy wynik:

% 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

Innymi słowy, z0 i z2 wydają się mieć zasadniczo identyczne wyniki. Myślisz, że to może być zbieg okoliczności? Ja nie....

W rzeczywistości posunąłbym się nawet do twierdzenia, że to niemożliwe aby czysty kod Pythona był lepszy niż ten. A jeśli możesz zrobić znacznie lepiej w module rozszerzeń C, wyobrażam sobie, że ludzie Pythona mogą być zainteresowani włączeniem Twojego kodu (lub wariacji na temat Twojego podejścia) do rdzenia Pythona. Python używa dict w wielu miejscach; optymalizacja jego operacji to wielka sprawa.

Możesz też napisać to jako

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

Tak jak Tony, ale (nic dziwnego) różnica w notacji okazuje się nie mieć żadnego mierzalnego efektu na wydajność. Użyj tego, co Ci odpowiada. Oczywiście ma absolutną rację zaznaczając, że wersja dwuznakowa jest znacznie łatwiejsza do zrozumienia.

 167
Author: zaphod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-10 02:32:55

W Pythonie 3.0 i nowszych można użyć collections.ChainMap który grupuje wiele dictów lub innych mapowań razem, aby utworzyć jeden, aktualizowalny widok:

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

Aktualizacja dla Pythona 3.5 i nowszych: możesz użyć PEP 448 rozszerzonego słownika do pakowania i rozpakowywania. To jest szybkie i proste:

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

Aktualizacja dla Pythona 3.9 i nowszych: możesz użyć Pep 584 union operator:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x | y
{'a': 1, 'b': 10, 'c': 11}
 146
Author: Raymond Hettinger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-11 06:43:11

Chciałem coś podobnego, ale z możliwością określenia, jak wartości na zduplikowanych kluczach zostały połączone, więc hacked to out (ale nie mocno testować). Oczywiście nie jest to pojedyncze wyrażenie, ale jedno wywołanie funkcji.

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
 127
Author: rcreswick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-13 19:56:21

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

Demonstracja:

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

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

print deepupdate(pluto_original, pluto_update)

Wyjścia:

{
    'name': 'Pluutoo',
    'details': {
        'color': 'blue',
        'tail': True
    }
}
Dzięki rednaw za edycje.
 101
Author: Stan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-18 11:19:15

Najlepsza wersja, jaką mogłem sobie wyobrazić, gdy nie używałem copy to:

from itertools import chain
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
dict(chain(x.iteritems(), y.iteritems()))
Jest szybszy niż dict(x.items() + y.items()), ale nie tak szybki jak n = copy(a); n.update(b), przynajmniej na Cpythonie. Ta wersja działa również w Pythonie 3, Jeśli zmienisz iteritems() na items(), co jest automatycznie wykonywane przez narzędzie 2to3.

Osobiście najbardziej podoba mi się ta wersja, ponieważ opisuje dość dobre to, co chcę w jednej składni funkcjonalnej. Jedynym drobnym problemem jest to, że nie jest całkowicie oczywiste, że wartości z y ma pierwszeństwo ponad wartościami z x, ale nie wydaje mi się, że trudno to rozgryźć.

 80
Author: driax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-14 18:55:15

Python 3.5 (PEP 448) pozwala na ładniejszą opcję składni:

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

Lub nawet

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

W Pythonie 3.9 używasz również | i / = z poniższym przykładem z PEP 584

d = {'spam': 1, 'eggs': 2, 'cheese': 3}
e = {'cheese': 'cheddar', 'aardvark': 'Ethel'}
d | e
# {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'aardvark': 'Ethel'}
 78
Author: Bilal Syed Hussain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-03 21:16:55
x = {'a':1, 'b': 2}
y = {'b':10, 'c': 11}
z = dict(x.items() + y.items())
print z

Dla elementów z kluczami w obu słownikach ('b'), możesz kontrolować, który z nich kończy się na wyjściu, umieszczając go na końcu.

 68
Author: Greg Hewgill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-02 07:49:27

Podczas gdy na pytanie już kilka razy udzielono odpowiedzi, to proste rozwiązanie problemu nie zostało jeszcze wymienione.

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

Jest tak szybki jak Z0 i zło Z2 wymienione powyżej, ale łatwy do zrozumienia i zmiany.

 55
Author: phobie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-14 16:12:33
def dict_merge(a, b):
  c = a.copy()
  c.update(b)
  return c

new = dict_merge(old, extras)
Wśród takich niejasnych i wątpliwych odpowiedzi, Ten świecący przykład jest jedynym i jedynym dobrym sposobem łączenia dictów w Pythonie, zatwierdzonym przez samego dictator for life[4]}Guido van Rossum[5]}! Ktoś inny zasugerował połowę tego, ale nie umieścił go w funkcji.
print dict_merge(
      {'color':'red', 'model':'Mini'},
      {'model':'Ferrari', 'owner':'Carl'})

Daje:

{'color': 'red', 'owner': 'Carl', 'model': 'Ferrari'}
 53
Author: Sam Watkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-06 09:30:07

Jeśli uważasz, że lambda są złe, nie czytaj dalej. Zgodnie z życzeniem, możesz napisać szybkie i efektywne w pamięci rozwiązanie za pomocą jednego wyrażenia:

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}

Jak sugerowano powyżej, używanie dwóch linii lub pisanie funkcji jest prawdopodobnie lepszym rozwiązaniem.

 47
Author: EMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-23 18:20:48

Bądź pythoniczny. Użyj :

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

>>> print z
{'a': 1, 'c': 11, 'b': 10}
 41
Author: Robino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-29 10:45:25

W python3, metoda items nie zwraca już listy, ale raczej widok, który działa jak zbiór. W tym przypadku musisz wziąć zestaw Unia ponieważ konkatenacja z + nie będzie działać:

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

Dla zachowania przypominającego python3 w wersji 2.7, metoda viewitems powinna działać zamiast items:

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

I tak wolę tę notację, ponieważ bardziej naturalne wydaje się myślenie o niej jako o operacji zespolonej, a nie konkatenacji (jak w tytule pokazy).

Edit:

Jeszcze kilka punktów dla Pythona 3. Po pierwsze, zauważ, że sztuczka dict(x, **y) nie będzie działać w Pythonie 3, chyba że klucze y są ciągami znaków.

Również odpowiedź Raymonda Hettingera Chainmap jest dość elegancka, ponieważ może przyjmować dowolną liczbę dictów jako argumentów, ale z dokumentów wygląda tak, jakby kolejno przeglądała listę wszystkich dictów dla każdego wyszukiwania:

Szukaj Szukaj mapuje kolejno, aż do znalezienia klucza.

Może to spowolnić, jeśli masz dużo wyszukiwania w aplikacji:

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

Więc o rząd wielkości wolniej dla wyszukiwania. Jestem fanem Chainmap, ale wygląda mniej praktycznie tam, gdzie może być wiele wyszukiwań.

 37
Author: beardc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

Dwa słowniki

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

N słowniki

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

sum ma złe wyniki. Zobacz https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

 28
Author: Mathieu Larose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-02 18:16:17

Proste rozwiązanie przy użyciu itertools, które zachowuje porządek (Ostatnie dicty mają pierwszeństwo)

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

I jego użycie:

>>> 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}
 28
Author: reubano,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-29 19:45:06

Nadużycie prowadzące do rozwiązania jednego wyrażenia dla odpowiedź Mateusza :

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

Powiedziałeś, że chcesz jedno wyrażenie, więc wykorzystałem lambda, aby powiązać nazwę, i krotki, aby zastąpić limit jednego wyrażenia lambda. Nie krępuj się.

Możesz to oczywiście zrobić, jeśli nie zależy ci na kopiowaniu:

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = (x.update(y), x)[1]
>>> z
{'a': 1, 'b': 10, 'c': 11}
 26
Author: Claudiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:53

Mimo że odpowiedzi były dobre dla tego słownikashallow , żadna z metod zdefiniowanych tutaj nie łączy głębokiego słownika.

Przykłady:

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

Można by się spodziewać wyniku czegoś takiego:

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

Zamiast tego otrzymujemy:

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

Wpis 'one' powinien mieć 'depth_2' i 'extra' jako elementy w słowniku, jeśli rzeczywiście było to połączenie.

Używanie łańcucha również nie działa:

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

Wyniki in:

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

Głębokie scalenie, które dało rcwesick, również tworzy ten sam wynik.

Tak, będzie działać scalanie przykładowych słowników, ale żaden z nich nie jest ogólnym mechanizmem scalania. Zaktualizuję to później, gdy napiszę metodę, która wykonuje prawdziwe scalanie.

 21
Author: Thanh Lim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-03 23:36:50

Jeśli nie masz nic przeciwko mutacji x,

x.update(y) or x

Proste, czytelne, wydajne. You know update() zawsze zwraca None, która jest wartością false. Tak więc powyższe wyrażenie będzie zawsze oceniać Do x, Po zaktualizowaniu go.

Większość metod mutujących w bibliotece standardowej (jak .update()) zwraca None zgodnie z konwencją, więc ten rodzaj wzorca będzie działał również na tych. Jeśli jednak używasz podklasy dict lub innej metody, która nie jest zgodna z tą konwencją, or może zwróć lewy operand, który może nie być tym, czego chcesz. Zamiast tego możesz użyć wyświetlacza krotki i indeksu, który działa niezależnie od tego, do czego pierwszy element jest oceniany (chociaż nie jest tak ładny): {]}

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

Jeśli nie masz jeszcze x W Zmiennej, możesz użyć lambda, aby utworzyć lokalny bez użycia instrukcji assignment. Oznacza to użycie lambda jako let expression, co jest powszechną techniką w językach funkcyjnych, ale może unpythonic.

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

Chociaż nie różni się to tak bardzo od następującego zastosowania nowego operatora morsa (tylko Python 3.8+):

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

Jeśli chcesz kopię, PEP 584 styl x | y jest najbardziej Pythoniczny na 3.9+. Jeśli musisz obsługiwać starsze wersje, PEP 448 styl {**x, **y} jest najłatwiejszy dla 3.5+. Ale jeśli nie jest to dostępne w Twojej (nawet starszej) wersji Pythona, wzór let również działa tutaj.

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

(jest to oczywiście niemal równoznaczne z (z := x.copy()).update(y) or z, Ale jeśli Twoja wersja Pythona jest wystarczająco Nowa, wtedy styl PEP 448 będzie dostępny.)

 17
Author: gilch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-25 18:59:20

(Tylko dla Python2. 7*; istnieją prostsze rozwiązania dla Python3*.)

Jeśli nie jesteś przeciwny importowaniu standardowego modułu bibliotecznego, możesz to zrobić

from functools import reduce

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

(bit or a w lambda jest konieczny, ponieważ dict.update zawsze zwraca None Po sukcesie.)

 14
Author: kjo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-28 13:13:27

Czerpiąc z pomysłów tu i gdzie indziej pojąłem funkcję:

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

Użycie (testowane w Pythonie 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})
Zamiast tego możesz użyć lambdy.
 13
Author: Bijou Trouvaille,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-19 05:49:19

Problem, który mam z rozwiązaniami wymienionymi do tej pory, polega na tym, że w połączonym słowniku wartość klucza " b " wynosi 10, ale moim zdaniem powinno być to 12. W tym świetle przedstawiam następujące:

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

Wyniki:

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}
 13
Author: upandacross,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 18:11:54

To takie głupie, że nic nie zwraca.
Po prostu używam prostej funkcji pomocnika do rozwiązania problemu:

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

Przykłady:

merge(dict1,dict2)
merge(dict1,dict2,dict3)
merge(dict1,dict2,dict3,dict4)
merge({},dict1,dict2)  # this one returns a new copy
 13
Author: GetFree,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-02 01:44:39
from collections import Counter
dict1 = {'a':1, 'b': 2}
dict2 = {'b':10, 'c': 11}
result = dict(Counter(dict1) + Counter(dict2))
To powinno rozwiązać twój problem.
 12
Author: reetesh11,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-30 13:04:00

Pojawi się nowa opcja, gdy Python 3.8 wyda (zaplanowane na 20 października 2019 r. ), Dzięki Pep 572: Assignment Expressions . Nowy operator wyrażenia przyporządkowania := pozwala przypisać wynik copy i nadal używać go do wywoływania update, pozostawiając połączony kod pojedynczym wyrażeniem, a nie dwoma instrukcjami, zmieniając:

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

Do:

(newdict := dict1.copy()).update(dict2)
Zachowując się identycznie pod każdym względem. Jeśli musisz również zwrócić wynik dict (poprosiłeś o wyrażenie zwracające dict; powyższe tworzy i przypisuje do newdict, ale nie zwraca go, więc nie możesz go użyć do przekazania argumentu do funkcji tak jak jest, a la myfunc((newdict := dict1.copy()).update(dict2))), a następnie po prostu dodaj {[15] } do końca (ponieważ update zwraca None, co jest falsyfikatem, następnie oceni i zwróci newdict jako wynik wyrażenia):{[50]]}
(newdict := dict1.copy()).update(dict2) or newdict

Ważne zastrzeżenie: ogólnie odradzam takie podejście na rzecz:

newdict = {**dict1, **dict2}

Metoda rozpakowywania jest bardziej przejrzyste (dla wszystkich, którzy wiedzą o uogólnionym rozpakowywaniu, , które powinieneś ), w ogóle nie wymaga nazwy dla wyniku (więc jest o wiele bardziej zwięzłe przy konstruowaniu tymczasowości, która jest natychmiast przekazywana do funkcji lub zawarta w list/tuple W przeciwieństwie do CP, CPython jest bardzo podobny do CP.]}

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

Ale robione na warstwie C, przy użyciu betonowego dict API, więc nie ma dynamicznego wyszukiwania/wiązania metod lub wywołanie funkcji (gdzie (newdict := dict1.copy()).update(dict2) jest nieuniknione identyczne z oryginalnym dwuliniowym w zachowaniu, wykonując pracę w dyskretnych krokach, z dynamicznym wyszukiwaniem/wiązaniem / wywoływaniem metod.

Jest również bardziej rozszerzalny, ponieważ łączenie trzechdict s jest oczywiste:
 newdict = {**dict1, **dict2, **dict3}

Gdzie użycie wyrażeń przypisania nie będzie skalowane w ten sposób; najbliższe, jakie można uzyskać, to:

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

Lub bez tymczasowej krotki None s, ale z testem prawdziwości z każdego wyniku None:

 (newdict := dict1.copy()).update(dict2) or newdict.update(dict3)
Każda z nich jest oczywiście znacznie brzydsza i zawiera dalsze nieefektywności (albo zmarnowane tymczasowe tuplez None S dla separacji przecinków, lub bezsensowne testowanie prawdziwości każdego update'S None zwrot dla or separacji).

Jedyną rzeczywistą zaletą podejścia assignment expression jest to, że:

  1. masz ogólny kod, który wymaga obsługi zarówno set s jak i dict s (oba obsługują copy i update, więc kod działa mniej więcej tak, jak można się tego spodziewać)
  2. oczekujesz, że otrzymasz dowolne obiekty podobne do dict , a nie tylko dict, i musisz zachować typ i semantykę lewej strony (zamiast kończyć się zwykłym dict). Chociaż myspecialdict({**speciala, **specialb}) może działać, wymagałoby to dodatkowego tymczasowego dict, a jeśli myspecialdict ma cechy zwykły dictnie może zachować (np. w oparciu o ostatni wygląd klucza; możesz chcieć takiego, który zachowuje porządek w oparciu o ostatni wygląd klucza, więc aktualizacja wartości również przenosi ją na koniec), wtedy semantyka byłaby błędna. Ponieważ wersja wyrażenia przyporządkowania używa nazwanych metod (które prawdopodobnie są przeciążone, aby zachowywać się odpowiednio), nigdy nie tworzy dict W OGÓLE (CHYBA że dict1 było już dict), zachowując oryginalny typ (i semantykę oryginalnego typu), a wszystko to unikając jakichkolwiek tymczasowo.
 12
Author: ShadowRanger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-28 17:49:22

Nowy w Pythonie 3.9: użyj operatora union (|), aby połączyć dict S podobne do set s:

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

Dla dopasowanych kluczy, prawo dict ma pierwszeństwo.

To również działa dla |=, aby zmodyfikować dict w miejscu:

>>> e |= d    # e = e | d
>>> e
{'a': 1, 'c': 3, 'b': 2}
 12
Author: xjcl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-29 21:49:39

Można to zrobić za pomocą jednego słownika:

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

Moim zdaniem najlepsza odpowiedź dla części 'single expression', ponieważ nie są potrzebne żadne dodatkowe funkcje i jest krótka.

 10
Author: RemcoGerlich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-17 14:47:23