Mam dwa słowniki w języku Python i chcę napisać jedno wyrażenie, które zwróci te dwa słowniki połączone. Potrzebowałbym tej update()
metody, gdyby zwrócił wynik zamiast modyfikować słownik 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ę uzyskać ten ostatni połączony słownik z
, a nie x
?
(Żeby być bardziej klarownym, dict.update()
szukam też rozwiązania konfliktu na ostatnim miejscu ).
python
dictionary
merge
Carl Meyer
źródło
źródło
z = x | y
Odpowiedzi:
Słowników
x
iy
,z
staje się płytko połączone słownik o wartości ody
zastąpienie tych zx
.W Pythonie 3.5 lub nowszym:
W Pythonie 2 (lub 3.4 lub niższym) napisz funkcję:
i teraz:
W Pythonie 3.9.0a4 lub większej (ostatecznej daty wydania ok października 2020): PEP-584 , omawiane tutaj , został wdrożony w celu dalszego uproszczenia to:
Wyjaśnienie
Załóżmy, że masz dwa dykta i chcesz połączyć je w nowy dykta bez zmiany oryginalnych dykt:
Pożądanym rezultatem jest uzyskanie nowego słownika (
z
) z połączonymi wartościami, a wartości drugiego dyktanda zastąpią wartości z pierwszego.Nowa składnia tego, zaproponowana w PEP 448 i dostępna od wersji Python 3.5 , to
I to jest rzeczywiście pojedyncze wyrażenie.
Zauważ, że możemy również połączyć się z literalną notacją:
i teraz:
Jest teraz wyświetlany jako zaimplementowany w harmonogramie wydań dla wersji 3.5, PEP 478 , a teraz znalazł się w dokumencie Co nowego w dokumencie Python 3.5 .
Ponieważ jednak wiele organizacji nadal korzysta z języka Python 2, możesz chcieć to zrobić w sposób zgodny z poprzednimi wersjami. Klasycznym sposobem Pythona, dostępnym w Python 2 i Python 3.0-3.4, jest zrobienie tego jako dwuetapowy proces:
W obu podejściach
y
zajmą drugie miejsce, a ich wartości zastąpiąx
wartości, a zatem'b'
wskażą na3
nasz wynik końcowy.Jeszcze nie w Pythonie 3.5, ale chcesz mieć jedno wyrażenie
Jeśli nie korzystasz jeszcze z języka Python 3.5 lub potrzebujesz napisać kod kompatybilny wstecz, a chcesz tego w jednym wyrażeniu , najbardziej wydajnym i poprawnym podejściem jest umieszczenie go w funkcji:
a następnie masz jedno wyrażenie:
Możesz także utworzyć funkcję scalającą nieokreśloną liczbę nagrań, od zera do bardzo dużej liczby:
Ta funkcja będzie działać w Pythonie 2 i 3 dla wszystkich nagrań. np. podane dykty
a
dog
:i pary wartość klucza w
g
weźmie górę nad dictsa
dof
, i tak dalej.Krytyka innych odpowiedzi
Nie używaj tego, co widzisz w wcześniej zaakceptowanej odpowiedzi:
W Pythonie 2 tworzysz dwie listy w pamięci dla każdego nagrania, tworzysz trzecią listę w pamięci o długości równej długości pierwszych dwóch razem, a następnie odrzucasz wszystkie trzy listy, aby utworzyć dykt. W Pythonie 3 to się nie powiedzie, ponieważ dodajesz dwa
dict_items
obiekty razem, a nie dwie listy -i musicie je jawnie utworzyć jako listy, np
z = dict(list(x.items()) + list(y.items()))
. Jest to marnotrawstwo zasobów i mocy obliczeniowej.Podobnie wzięcie unii
items()
w Pythonie 3 (viewitems()
w Pythonie 2.7) również nie powiedzie się, gdy wartości są obiektami nieukończonymi (np. Listami). Nawet jeśli twoje wartości są haszowalne, ponieważ zestawy są semantycznie nieuporządkowane, zachowanie jest niezdefiniowane pod względem pierwszeństwa. Więc nie rób tego:Ten przykład pokazuje, co się dzieje, gdy wartości są nie do zniesienia:
Oto przykład, w którym y powinno mieć pierwszeństwo, ale zamiast tego wartość z x jest zachowywana z powodu dowolnej kolejności zbiorów:
Kolejny hack, którego nie powinieneś używać:
Korzysta z
dict
konstruktora i jest bardzo szybki i efektywny pod względem pamięci (nawet nieco bardziej niż w naszym dwuetapowym procesie), ale chyba, że wiesz dokładnie, co się tutaj dzieje (to znaczy drugi dykt jest przekazywany jako argumenty słów kluczowych do dyktatora konstruktor), jest trudny do odczytania, nie jest to zamierzone użycie, a więc nie jest Pythonic.Oto przykład zastosowania korygowanego w programie django .
Dicts są przeznaczone do pobierania kluczy haszujących (np. Frozensets lub krotek), ale ta metoda kończy się niepowodzeniem w Pythonie 3, gdy klucze nie są łańcuchami.
Z listy mailingowej Guido van Rossum, twórca języka, napisał:
i
Rozumiem (podobnie jak rozumie twórcę języka ), że zamierzonym zastosowaniem
dict(**y)
jest tworzenie dykt dla celów czytelności, np .:zamiast
Odpowiedź na komentarze
Ponownie, nie działa dla 3, gdy klucze nie są łańcuchami. Implikowana umowa wywoływania polega na tym, że przestrzenie nazw przyjmują zwykłe dyktanda, podczas gdy użytkownicy muszą przekazywać tylko argumenty słów kluczowych, które są ciągami znaków. Wymuszały to wszystkie inne kallaby.
dict
złamał tę spójność w Pythonie 2:Ta niespójność była zła, biorąc pod uwagę inne implementacje Pythona (Pypy, Jython, IronPython). Dlatego zostało to naprawione w Pythonie 3, ponieważ użycie to może być przełomową zmianą.
Oświadczam, że umyślne pisanie kodu, który działa tylko w jednej wersji języka lub działa tylko z pewnymi arbitralnymi ograniczeniami, jest złośliwe.
Więcej komentarzy:
Moja odpowiedź:
merge_two_dicts(x, y)
właściwie wydaje mi się znacznie jaśniejsza, jeśli naprawdę martwimy się o czytelność. I nie jest kompatybilny do przodu, ponieważ Python 2 jest coraz bardziej przestarzały.Tak. Muszę odesłać cię z powrotem do pytania, które dotyczy płytkiego połączenia dwóch słowników, przy czym pierwsze wartości są zastępowane przez drugie - jednym wyrażeniem.
Zakładając dwa słowniki, można rekurencyjnie łączyć je w jedną funkcję, ale należy uważać, aby nie modyfikować nagrań z żadnego źródła, a najpewniejszym sposobem uniknięcia tego jest zrobienie kopii podczas przypisywania wartości. Ponieważ klucze muszą być haszowalne i dlatego zwykle są niezmienne, ich kopiowanie nie ma sensu:
Stosowanie:
Wymyślenie nieprzewidzianych okoliczności dla innych typów wartości wykracza daleko poza zakres tego pytania, dlatego wskażę moją odpowiedź na pytanie kanoniczne dotyczące „Scalenia słowników” .
Mniej wydajne, ale poprawne ad-hoki
Podejścia te są mniej wydajne, ale zapewnią prawidłowe zachowanie. Będą one znacznie mniej wydajnych niż
copy
aupdate
lub nowy rozpakowanie ponieważ iterację każdej pary klucz-wartość na wyższym poziomie abstrakcji, ale zrobić respektować porządek pierwszeństwa (ostatnie dicts mają pierwszeństwo)Można również ręcznie połączyć łańcuchy w ramach rozumienia:
lub w Pythonie 2.6 (i być może już w wersji 2.4, kiedy wprowadzono wyrażenia generatora):
itertools.chain
połączy iteratory z parami klucz-wartość we właściwej kolejności:Analiza wydajności
Zamierzam tylko przeprowadzić analizę wydajności, o której wiadomo, że zachowuje się poprawnie.
Poniższe czynności są wykonywane w systemie Ubuntu 14.04
W Python 2.7 (systemowy Python):
W Python 3.5 (deadsnakes PPA):
Zasoby dotyczące słowników
źródło
{**{(0, 1):2}}
->{(0, 1): 2}
z = {**x, **y}
naprawdę mnie stymulująx | y
W twoim przypadku możesz:
Spowoduje to, jak chcesz, wstawienie ostatniego dykta
z
i sprawi, że wartość kluczab
zostanie poprawnie zastąpiona wartością drugiego (y
) dykta:Jeśli używasz Python 3, jest to tylko trochę bardziej skomplikowane. Aby utworzyć
z
:Jeśli używasz języka Python w wersji 3.9.0a4 lub nowszej, możesz bezpośrednio użyć:
źródło
Alternatywa:
źródło
Update
nie jest jedną z podstawowych funkcji, z których ludzie często korzystają.(lambda z: z.update(y) or z)(x.copy())
: PKolejna, bardziej zwięzła opcja:
Uwaga : stała się popularną odpowiedzią, ale ważne jest, aby zaznaczyć, że jeśli
y
ma jakieś klucze nieciągłe, fakt, że to w ogóle działa, jest nadużyciem szczegółów implementacji CPython i nie działa w Pythonie 3, lub w PyPy, IronPython lub Jython. Ponadto Guido nie jest fanem . Nie mogę więc polecić tej techniki przenośnemu kodowi zgodnemu z przyszłym kodem lub implementacji krzyżowej, co naprawdę oznacza, że należy go całkowicie unikać.źródło
To prawdopodobnie nie będzie popularna odpowiedź, ale prawie na pewno nie chcesz tego robić. Jeśli chcesz kopii, która jest scaleniem, użyj kopiowania (lub głębokiej kopii , w zależności od tego, czego chcesz), a następnie zaktualizuj. Dwa wiersze kodu są znacznie bardziej czytelne - bardziej Pythonic - niż tworzenie pojedynczych wierszy za pomocą .items () + .items (). Jawne jest lepsze niż niejawne.
Ponadto, korzystając z .items () (wcześniejszych niż Python 3.0), tworzysz nową listę zawierającą elementy ze słownika. Jeśli twoje słowniki są duże, jest to dość dużo narzutu (dwie duże listy, które zostaną wyrzucone, gdy tylko powstanie scalony słownik). update () może działać wydajniej, ponieważ może przejść przez drugi dyktat element po elemencie.
Pod względem czasu :
IMO małe spowolnienie między dwoma pierwszymi jest tego warte dla czytelności. Ponadto argumenty słów kluczowych do tworzenia słownika zostały dodane tylko w Pythonie 2.3, natomiast copy () i update () będą działać w starszych wersjach.
źródło
W odpowiedzi uzupełniającej zapytałeś o względną skuteczność tych dwóch alternatyw:
Na mojej maszynie przynajmniej (dość zwyczajny x86_64 z uruchomionym Pythonem 2.5.2) alternatywa
z2
jest nie tylko krótsza i prostsza, ale także znacznie szybsza. Możesz to samodzielnie sprawdzić za pomocątimeit
modułu dostarczonego z Pythonem.Przykład 1: identyczne słowniki odwzorowujące do siebie 20 kolejnych liczb całkowitych:
z2
wygrywa około 3,5 razy. Różne słowniki wydają się przynosić całkiem odmienne wyniki, alez2
zawsze wydają się wychodzić z przodu. (Jeśli otrzymujesz niespójne wyniki dla tego samego testu, spróbuj podać-r
liczbę większą niż domyślna 3.)Przykład 2: nienakładające się słowniki odwzorowujące 252 krótkie ciągi znaków na liczby całkowite i odwrotnie:
z2
wygrywa około 10 razy. To całkiem spore zwycięstwo w mojej książce!Po porównaniu tych dwóch zastanawiałem się, czy
z1
słabą wydajność można przypisać narzutowi związanemu z budowaniem dwóch list przedmiotów, co z kolei skłoniło mnie do zastanowienia się, czy ta odmiana mogłaby działać lepiej:Kilka szybkich testów, np
doprowadzić mnie do wniosku, że
z3
jest nieco szybszy niżz1
, ale nie tak szybki jakz2
. Zdecydowanie nie warte wszystkich dodatkowych pisania.W tej dyskusji wciąż brakuje czegoś ważnego, jakim jest porównanie wydajności tych alternatyw z „oczywistym” sposobem łączenia dwóch list: za pomocą
update
metody. Aby spróbować zachować równowagę z wyrażeniami, z których żadne nie modyfikuje x ani y, zamierzam utworzyć kopię x zamiast modyfikować ją w miejscu, w następujący sposób:Typowy wynik:
Innymi słowy,
z0
iz2
wydają się mieć zasadniczo identyczną wydajność. Czy uważasz, że to może być zbieg okoliczności? Ja nie....W rzeczywistości posunąłbym się nawet do stwierdzenia, że czysty kod Pythona nie jest w stanie zrobić nic lepszego. A jeśli możesz zrobić znacznie lepiej w module rozszerzenia C, wyobrażam sobie, że ludzie Pythona mogliby być zainteresowani włączeniem twojego kodu (lub zmiany twojego podejścia) do rdzenia Pythona. Python używa
dict
w wielu miejscach; optymalizacja operacji to wielka sprawa.Możesz również napisać to jako
tak jak Tony, ale (co nie jest zaskakujące) różnica w notacji nie ma żadnego mierzalnego wpływu na wydajność. Użyj tego, co najbardziej Ci odpowiada. Oczywiście ma absolutną rację, wskazując, że wersja dwuskładnikowa jest znacznie łatwiejsza do zrozumienia.
źródło
items()
nie jest do zaakceptowania iiteritems
nie istnieje.W Pythonie 3.0 i nowszych
collections.ChainMap
wersjach możesz użyć grupowania wielu nagrań lub innych mapowań, aby utworzyć jeden, aktualizowany widok:Aktualizacja dla Python 3.5 i nowszych : Możesz używać rozszerzonego pakowania i rozpakowywania słownika PEP 448 . Jest to szybkie i łatwe:
źródło
del
powiedz, że ChainMap c usunie pierwsze mapowanie tego klucza.dict
tego uniknąć, tj .:dict(ChainMap({}, y, x))
Chciałem czegoś podobnego, ale z możliwością określenia, w jaki sposób wartości na duplikatach kluczy zostały scalone, więc zhackowałem to (ale nie przetestowałem go zbyt mocno). Oczywiście nie jest to pojedyncze wyrażenie, ale pojedyncze wywołanie funkcji.
źródło
Rekurencyjnie / głęboka aktualizacja nagrania
Demonstracja:
Wyjścia:
Dzięki rednaw za zmiany.
źródło
Najlepszą wersją, jaką mogłem pomyśleć, nie używając kopii, byłoby:
Jest szybszy niż,
dict(x.items() + y.items())
ale nie tak szybkin = copy(a); n.update(b)
, przynajmniej na CPython. Ta wersja działa również w Pythonie 3, jeśli zmienisziteritems()
naitems()
, co jest automatycznie wykonywane przez narzędzie 2to3.Osobiście najbardziej podoba mi się ta wersja, ponieważ opisuje dość dobrze to, czego chcę w pojedynczej składni funkcjonalnej. Jedynym drobnym problemem jest to, że nie jest całkowicie oczywiste, że wartości z y mają pierwszeństwo przed wartościami z x, ale nie sądzę, że trudno to rozgryźć.
źródło
Python 3.5 (PEP 448) pozwala na ładniejszą opcję składni:
Lub nawet
W Pythonie 3.9 używasz także | i | = w poniższym przykładzie z PEP 584
źródło
dict(x, **y)
rozwiązanie? Jak wspomniałeś (@CllMeyer) w notatce swojej własnej odpowiedzi ( stackoverflow.com/a/39858/2798610 ), Guido uważa to rozwiązanie za nielegalne .dict(x, **y)
(bardzo dobrego) powodu, że polega ony
tylko na posiadaniu kluczy, które są poprawnymi nazwami argumentów słów kluczowych (chyba że używasz CPython 2.7, gdzie oszukiwa konstruktor dict). To zastrzeżenie / ograniczenie nie dotyczy PEP 448, który uogólnia**
składnię rozpakowywania w celu dyktowania literałów. To rozwiązanie ma tę samą zwięzłość, codict(x, **y)
bez wad.W przypadku elementów z kluczami w obu słownikach („b”) możesz kontrolować, który z nich znajdzie się na wyjściu, umieszczając go jako ostatni.
źródło
Chociaż na to pytanie udzielono już odpowiedzi kilka razy, to proste rozwiązanie problemu nie zostało jeszcze wymienione.
Jest tak szybki jak Z0 i wspomniane powyżej zło Z2, ale łatwo go zrozumieć i zmienić.
źródło
z4 = {}
i zmień następny wiersz naz4 = x.copy()
- lepszy niż dobry kod nie robi niepotrzebnych rzeczy (co czyni go jeszcze bardziej czytelnym i łatwym w utrzymaniu).Wśród takich podejrzanych i wątpliwych odpowiedzi, ten lśniący przykład jest jedynym i jedynym dobrym sposobem na połączenie dyktatów w Pythonie, popieranym przez samego dyktatora Guido van Rossuma ! Ktoś inny zasugerował połowę tego, ale nie nadał mu żadnej funkcji.
daje:
źródło
Jeśli uważasz, że lambdas są złe, nie czytaj dalej. Zgodnie z życzeniem możesz napisać szybkie i efektywne pod względem pamięci rozwiązanie z jednym wyrażeniem:
Jak sugerowano powyżej, użycie dwóch linii lub napisanie funkcji jest prawdopodobnie lepszym sposobem.
źródło
Bądź pytoniczny. Użyj zrozumienia :
źródło
def dictmerge(*args): return {i:d[i] for d in args for i in d}
z={k: v for d in (x, y) for k, v in d.items()}
W python3
items
metoda nie zwraca już listy , ale widok , który działa jak zestaw. W takim przypadku musisz wziąć ustawiony związek, ponieważ konkatenacja z+
nie będzie działać:W przypadku zachowania podobnego do python3 w wersji 2.7
viewitems
metoda powinna działać zamiastitems
:W każdym razie wolę ten zapis, ponieważ bardziej naturalne wydaje się myślenie o nim jako o określonej operacji związkowej niż o konkatenacji (jak pokazuje tytuł).
Edytować:
Jeszcze kilka punktów dla Pythona 3. Po pierwsze, zauważ, że
dict(x, **y)
sztuczka nie będzie działać w Pythonie 3, chyba że klucze wy
są ciągami.Ponadto odpowiedź Chainmap Raymonda Hettingera jest dość elegancka, ponieważ może przyjmować dowolną liczbę dykt jako argumentów, ale z dokumentów wygląda tak, jakby sekwencyjnie przeglądała listę wszystkich dykt dla każdego wyszukiwania:
Może to spowolnić działanie, jeśli masz dużo wyszukiwań w swojej aplikacji:
A więc o rząd wielkości wolniej dla odnośników. Jestem fanem Chainmap, ale wygląda mniej praktycznie tam, gdzie może być wiele odnośników.
źródło
Nadużycie prowadzące do jednoprecyzyjnego rozwiązania dla odpowiedzi Matthew :
Powiedziałeś, że chcesz jednego wyrażenia, więc nadużyłem
lambda
wiązania nazwy i krotek, aby zastąpić limit jednego wyrażenia lambdy. Nie krępuj się.Możesz to oczywiście zrobić, jeśli nie chcesz kopiować:
źródło
Proste rozwiązanie za pomocą itertools, które zachowuje porządek (ostatnie dykty mają pierwszeństwo)
I to jest użycie:
źródło
Dwa słowniki
n słowniki
sum
ma słabą wydajność. Zobacz https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/źródło
Mimo że odpowiedzi były dobre dla tego płytkiego słownika, żadna z zdefiniowanych tutaj metod nie wykonuje głębokiego scalenia słownika.
Przykłady:
Można się spodziewać czegoś takiego:
Zamiast tego otrzymujemy:
Wpis „one” powinien mieć w swym słowniku elementy „depth_2” i „extra”, jeśli naprawdę był to scalenie.
Korzystanie z łańcucha również nie działa:
Prowadzi do:
Głębokie scalenie, które wykonał rcwesick, również daje ten sam rezultat.
Tak, będzie działać, aby scalić przykładowe słowniki, ale żaden z nich nie jest ogólnym mechanizmem scalania. Zaktualizuję to później, gdy napiszę metodę, która dokonuje prawdziwego scalenia.
źródło
(Tylko dla Python2.7 *; istnieją prostsze rozwiązania dla Python3 *.)
Jeśli nie masz nic przeciwko importowaniu standardowego modułu biblioteki, możesz to zrobić
(
or a
Trochę wlambda
jest konieczne, ponieważdict.update
zawsze powracaNone
po sukcesie).źródło
Jeśli nie masz nic przeciwko mutowaniu
x
,Prosty, czytelny, wydajny. Wiesz, że
update()
zawsze zwracaNone
, co jest wartością fałszywą. Tak więc powyższe wyrażenie zawsze będzie oceniaćx
po aktualizacji.Metody mutacji w standardowej bibliotece (podobnie jak
.update()
) zwracane sąNone
zgodnie z konwencją, więc ten wzór będzie działał również na nich. Jeśli używasz metody niezgodnej z tą konwencją,or
może nie działać. Ale zamiast tego możesz użyć wyświetlania krotek i indeksu, aby uczynić je pojedynczym wyrażeniem. Działa to niezależnie od tego, co ocenia pierwszy element.Jeśli nie masz
x
jeszcze zmiennej, możesz użyćlambda
do utworzenia lokalnego bez użycia instrukcji przypisania. Sprowadza się to do użycialambda
jako wyrażenia let , co jest powszechną techniką w językach funkcjonalnych, ale może nie jest mityczne.Chociaż nie różni się tak bardzo od następującego zastosowania nowego operatora morsa (tylko Python 3.8+):
Jeśli potrzebujesz kopii, styl PEP 448 jest najłatwiejszy
{**x, **y}
. Ale jeśli nie jest to dostępne w (starszej) wersji Pythona, wzór let również tutaj działa.(Jest to oczywiście równoważne
(z := x.copy()).update(y) or z
, ale jeśli twoja wersja Pythona jest wystarczająco nowa, styl PEP 448 będzie dostępny.)źródło
Opierając się na pomysłach tu i gdzie indziej, zrozumiałem funkcję:
Użycie (testowane w Pythonie 3):
Zamiast tego możesz użyć lambda.
źródło
Problem, który mam z dotychczas wymienionymi rozwiązaniami, polega na tym, że w połączonym słowniku wartość klucza „b” wynosi 10, ale moim zdaniem powinna to być wartość 12. W tym świetle przedstawiam:
Wyniki:
źródło
cytoolz.merge_with
( toolz.readthedocs.io/en/latest/… )Jest tak głupie, że
.update
nic nie zwraca.Po prostu używam prostej funkcji pomocnika, aby rozwiązać problem:
Przykłady:
źródło
To powinno rozwiązać twój problem.
źródło
Można to zrobić za pomocą pojedynczego rozumienia:
Moim zdaniem najlepsza odpowiedź na część „pojedyncze wyrażenie”, ponieważ nie są potrzebne żadne dodatkowe funkcje, i jest krótka.
źródło
Pojawi się nowa opcja, kiedy wydania Python 3.8 ( zaplanowane na 20 października 2019 r. ), Dzięki PEP 572: Wyrażenia przypisania . Nowy operator wyrażeń przypisania
:=
pozwala przypisać wynikcopy
i nadal używać go do wywoływaniaupdate
, pozostawiając połączony kod pojedynczym wyrażeniem zamiast dwóch instrukcji, zmieniając:do:
zachowując się jednakowo pod każdym względem. Jeśli musisz również zwrócić wynikowy
dict
(poprosiłeś o wyrażenie zwracającedict
; powyższe tworzy i przypisuje jenewdict
, ale nie zwraca, więc nie możesz użyć go do przekazania argumentu do funkcji w obecnej postacimyfunc((newdict := dict1.copy()).update(dict2))
) , a następnie po prostu dodajor newdict
na końcu (ponieważupdate
zwracaNone
, co jest fałszem, będzie wówczas oceniać i zwracaćnewdict
jako wynik wyrażenia):Ważne zastrzeżenie: ogólnie odradzam takie podejście na rzecz:
Podejście do rozpakowywania jest jaśniejsze (dla każdego, kto wie o uogólnionym rozpakowaniu w pierwszej kolejności, co powinieneś ), w ogóle nie wymaga nazwy wyniku (więc jest o wiele bardziej zwięzłe przy tworzeniu tymczasowego, który jest natychmiast przekazywany do funkcjonuje lub jest zawarty w
list
/tuple
dosłownym lub podobnym) i jest prawie na pewno także szybszy, będąc (na CPython) w przybliżeniu równoważnym z:ale zrobiono to w warstwie C, używając konkretnego
dict
interfejsu API, więc nie jest związane z dynamicznym wyszukiwaniem / wiązaniem metody ani obciążeniem wywołania funkcji(newdict := dict1.copy()).update(dict2)
jest nieunikniony identyczny z oryginalnym dwóch tulei w zachowaniu, wykonując prace w oddzielnych etapach, z dynamicznym odnośnika / bindowanie / wywoływanie metod.Jest również bardziej rozszerzalny, ponieważ połączenie trzech
dict
s jest oczywiste:gdzie użycie wyrażeń przypisania nie będzie tak skalowane; najbliższy byłby to:
lub bez tymczasowej krotki
None
s, ale z testowaniem prawdziwości każdegoNone
wyniku:jeden z co jest oczywiście dużo mniej efektowna, a ponadto zawiera niewydolności (albo zmarnowany czasowy
tuple
odNone
S do oddzielania przecinkiem czy niepotrzebnych testów truthiness każdegoupdate
„SNone
powrotu door
rozdzielenia).Jedyną prawdziwą zaletą podejścia do wyrażania przypisań jest:
set
S idict
S (obie z nich obsługujecopy
iupdate
tak kod działa mniej więcej jak chcesz go do spodziewać)dict
sam, i musisz zachować typ i semantykę lewej strony (zamiast kończyć się zwykłymdict
). Chociażmyspecialdict({**speciala, **specialb})
może działać, wymagałoby to dodatkowego tymczasowego działaniadict
, a jeślimyspecialdict
ma funkcje, których zwykłydict
nie może zachować (np. Zwykłedict
s teraz zachowują kolejność na podstawie pierwszego pojawienia się klucza, a wartość na podstawie ostatniego pojawienia się klucza; taki, który zachowuje porządek na podstawie ostatniego pojawienie się klucza, więc aktualizacja wartości przesuwa go również do końca), to semantyka byłaby błędna. Ponieważ wersja wyrażenia przypisania korzysta z nazwanych metod (które są prawdopodobnie przeciążone, aby się odpowiednio zachowywać), nigdy nie tworzydict
w ogóle (chyba żedict1
było to adict
), zachowując typ oryginalny (i semantykę typu oryginalnego), a wszystko to przy jednoczesnym unikaniu tymczasowości.źródło
źródło
x
swoją kopię. Jeślix
jest argumentem funkcji, to nie zadziała (patrz przykład )