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

Mam dwa słowniki Pythona i chcę napisać jedno wyrażenie, które zwróci te dwa słowniki, połączone. Metoda update() byłaby tym, czego potrzebuję, jeśli zwróci wynik zamiast zmodyfikować dict w 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ę dostać ten ostatni scalony dict 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: wim, 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ę połączonym słownikiem z wartościami z y, zastępując te z x.

  • W Pythonie 3.5 lub nowszym:

    z = {**x, **y}
    w = {'foo': 'bar', 'baz': 'qux', **y}  # merge a dict with literal values
    
  • 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
    

    I

    z = merge_two_dicts(x, y)
    

Wyjaśnienie

Powiedzmy, że masz dwa dicty i chcesz je połączyć w nowy dict bez zmiany oryginalnych dict:

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 dict zastępują wartości z pierwszego.

>>> z
{'a': 1, 'b': 3, 'c': 4}
W Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5, Pythonie 3.5]}
z = {**x, **y}

I rzeczywiście jest to jedno wyrażenie. Jest teraz pokazywany jako zaimplementowany w harmonogramie wydania dla 3.5, PEP 478, a teraz zrobił jego droga do Co nowego w Pythonie 3.5 dokumentu.

Jednakże, ponieważ wiele organizacji nadal korzysta z Pythona 2, możesz chcieć to zrobić w sposób zgodny wstecz. 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 drugie, a jego wartości zastąpią x wartości, więc 'b' wskaże 3 w naszym ostatecznym wyniku.

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

Jeśli nie używasz jeszcze Pythona 3.5 lub musisz napisać wstecznie zgodny kod i chcesz to zrobić w pojedynczym wyrażeniu , najbardziej wydajnym przy prawidłowym podejściu jest umieszczenie go w funkcji:

def merge_two_dicts(x, y):
    """Given two dicts, 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ę dictów, od zera do bardzo dużej liczby:

def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result

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

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

I pary wartości klucza w {[38] } będą miały pierwszeństwo przed dictami 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 nieokreślone 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 wydajny w pamięci (nawet nieco bardziej-niż nasz dwuetapowy proces), ale jeśli nie wiesz dokładnie, co się tutaj dzieje (to znaczy, drugi dict jest przekazywany jako argumenty kluczowe do konstruktora dict), jest to trudne do odczytania, nie jest to zamierzone użycie, a więc nie jest to Pythonic.

Oto przykład użycia naprawionego w django .

Dict są przeznaczone do przyjmowania kluczy hashable (np. frozensets lub krotki), ale ta metoda zawodzi w Pythonie 3, gdy klucze nie są struny.

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

I ' m fine with 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.

To jest moje zrozumienie (jak również jako zrozumienie twórcy języka), że zamierzone użycie dict(**y) ma na celu stworzenie dyktowania dla celów czytelności, na przykład:

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 dla kluczy łańcuchowych, jest bezpośrednią konsekwencją działania parametrów słów kluczowych, a nie krótkiego dict. Użycie w tym miejscu operatora ** nie jest też nadużyciem mechanizmu, w rzeczywistości ** został zaprojektowany właśnie po to, aby przekazywać dicty 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 dicty, 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, biorąc pod uwagę inne implementacje Python (Pypy, Jython, IronPython). W ten sposób został on poprawiony w Pythonie 3, ponieważ to użycie może być przełomową zmianą.

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.

Kolejny komentarz:

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

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

Mniej wydajny, ale poprawny Ad-hocs

[59]}te podejścia są mniej wydajne, ale zapewnią poprawne zachowanie. Będą one znacznie mniej performatywne niż copy i update lub nowe rozpakowywanie, ponieważ iterują przez każdą parę klucz-wartość na wyższym poziomie abstrakcji, aleszanują kolejność pierwszeństwo (Ostatnie dicki mają pierwszeństwo) Można również ręcznie łańcuchować dict 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())

itertools.chain będzie łączyć Iteratory nad parami klucz-wartość w odpowiedniej kolejności:

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

Analiza Wydajności

Przeprowadzę tylko analizę wydajności zwyczajów, o których wiadomo, że zachowują się poprawnie.

import timeit
Na Ubuntu 14.04 wykonujemy następujące czynności]}

W Pythonie 2.7 (Python systemowy):

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(), y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

W Pythonie 3.5 (deadsnakes PPA):

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

Zasoby na słownikach

- wykład Raymonda Hettingera na Pycon 2017 {65]}
 3562
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
2018-07-03 17:02:21

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

z = dict(x.items() + 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(x.items() + y.items())
>>> z
{'a': 1, 'c': 11, 'b': 10}

Jeśli używasz Pythona 3, jest to tylko trochę bardziej skomplikowane. Aby utworzyć z:

>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10}
 1456
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
2018-08-29 17:18:02

Alternatywa:

z = x.copy()
z.update(y)
 559
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.

 278
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.
 171
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.

 118
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

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

W Pythonie 3 możesz użyć Kolekcje.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 = ChainMap({}, y, x)
>>> for k, v in z.items():
        print(k, '-->', v)

a --> 1
b --> 10
c --> 11
 77
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
2014-09-27 08:12:41

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.
 61
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źć.

 54
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}
 42
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
2015-02-26 21:27:52
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.

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

 35
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'}
 33
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.

 25
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}
 20
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ń.

 19
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

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

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

import itertools as it
merge = lambda *args: dict(it.chain.from_iterable(it.imap(dict.iteritems, 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}
 13
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
2016-09-06 11:30:16

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/

 11
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

W Pythonie 3:

import collections
a = {1: 1, 2: 2}
b = {2: 3, 3: 4}
c = {3: 5}

r = dict(collections.ChainMap(a, b, c))
print(r)

Out:

{1: 1, 2: 2, 3: 4}

Docs: https://docs.python.org/3/library/collections.html#collections.ChainMap :

 11
Author: Skyduy,
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-24 07:24:50

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.

 9
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

Dla Pythona 2:

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

Dla Pythona 3:

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

Daje wyjście: {'a': 1, 'c': 11, 'b': 10}

 8
Author: Kalpesh Dusane,
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-01 06:29:01

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.
 7
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
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}
 5
Author: John La Rooy,
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-11-13 10:01:31

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

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.

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

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

 5
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

W Pythonie 3.5 możesz użyć unpack ** w celu utworzenia nowego słownika. Metoda ta nie została wykazana w poprzednich odpowiedziach. Ponadto, lepiej jest użyć {} zamiast dict(). Ponieważ {} jest literałem Pythona, a dict() zawiera wywołanie funkcji.

dict1 = {'a':1}
dict2 = {'b':2}
new_dict = {**dict1, **dict2}
>>>new_dict
{'a':1, 'a':2}
 5
Author: levi,
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-28 00:33:55