Dodanie collections.defaultdict
Pythona 2,5 znacznie zmniejsza zapotrzebowanie na dict
„s setdefault
metody. To pytanie dotyczy naszej wspólnej edukacji:
- Co jest
setdefault
nadal przydatne w Pythonie 2.6 / 2.7? - Jakie popularne przypadki użycia
setdefault
zostały zastąpionecollections.defaultdict
?
python
dictionary
setdefault
Eli Bendersky
źródło
źródło
Odpowiedzi:
Można powiedzieć, że
defaultdict
jest przydatny w przypadku ustawień domyślnych przed wypełnieniem dykta isetdefault
jest przydatny do ustawienia domyślnych podczas lub po wypełnieniu dykta .Prawdopodobnie najczęstszy przypadek użycia: grupowanie elementów (w nieposortowanych danych, w przeciwnym razie użyj
itertools.groupby
)Czasami chcesz się upewnić, że określone klucze istnieją po utworzeniu nagrania.
defaultdict
nie działa w tym przypadku, ponieważ tworzy klucze tylko w przypadku jawnego dostępu. Myślisz, że używasz czegoś HTTP z wieloma nagłówkami - niektóre są opcjonalne, ale chcesz dla nich wartości domyślne:źródło
defaultdict
. Czy możesz podać przykład tego, co masz na myśli w pierwszym akapicie?setdefault
. Zdefaultdict
drugiej strony nie działałoby, gdyby nie wszystkiedefaultvalues
były równe (tzn. Niektóre są,0
a niektóre są[]
).headers = dict(optional_headers)
. W przypadku, gdy wartości domyślne nie są równe. Wynik końcowy jest taki sam, jakbyś najpierw otrzymał nagłówki HTTP, a następnie ustawił wartości domyślne dla tych, których nie otrzymałeś. I jest całkiem użyteczny, jeśli już go maszoptional_headers
. Wypróbuj mój 2-etapowy kod i porównaj go z własnym, a zobaczysz, co mam na myśli.new.setdefault(key, []).append(value)
defaultdict
nawet lepszej niżsetdefault
(więc gdzie jest teraz przypadek użycia?). TakżeChainMap
lepiej obsługiwaćhttp
przykład, IMO.Często używam
setdefault
dla słów kluczowych argumentów, takich jak w tej funkcji:Doskonale nadaje się do poprawiania argumentów w opakowaniach wokół funkcji, które pobierają argumenty słów kluczowych.
źródło
defaultdict
jest świetny, gdy domyślna wartość jest statyczna, jak nowa lista, ale nie tak bardzo, jeśli jest dynamiczna.Na przykład potrzebuję słownika do mapowania ciągów znaków na unikalne int.
defaultdict(int)
zawsze użyje 0 jako wartości domyślnej. Podobniedefaultdict(intGen())
zawsze daje 1.Zamiast tego użyłem zwykłego dykta:
Zauważ, że
dict.get(key, nextID())
jest to niewystarczające, ponieważ muszę również móc odwoływać się do tych wartości później.intGen
to niewielka klasa, którą buduję, która automatycznie zwiększa liczbę całkowitą i zwraca jej wartość:Jeśli ktoś ma na to sposób
defaultdict
, chciałbym to zobaczyć.źródło
intGen
zitertools.count().next
.nextID()
wartość będzie zwiększana za każdym razemmyDict.setdefault()
, gdy zostanie wywołana, nawet jeśli zwracana wartość nie jest używana jakostrID
. Wydaje się to w pewnym sensie marnotrawstwem i ilustruje jedną z rzeczy, którychsetdefault()
ogólnie nie lubię - a mianowicie to, że zawsze ocenia swójdefault
argument, czy faktycznie się przyzwyczai.defaultdict
:myDict = defaultdict(lambda: nextID())
. PóźniejstrID = myDict[myStr]
w pętli.myDict = defaultdict(nextID)
?Używam,
setdefault()
gdy chcę wartość domyślną wOrderedDict
. Nie jest to standardowy zbiór Pythona, który ma zarówno, ale są sposoby, aby wdrożyć taką kolekcję.źródło
Ponieważ większość odpowiedzi podaje
setdefault
lubdefaultdict
pozwala ustawić wartość domyślną, gdy klucz nie istnieje. Chciałbym jednak zwrócić uwagę na małe zastrzeżenie dotyczące przypadków użyciasetdefault
. Podczas wykonywania interpretera Pythonsetdefault
zawsze ocenia drugi argument funkcji, nawet jeśli klucz istnieje w słowniku. Na przykład:Jak widać,
print
został również wykonany, mimo że 2 już istniały w słowniku. Staje się to szczególnie ważne, jeśli planujeszsetdefault
na przykład użyć do takiej optymalizacjimemoization
. Jeśli dodasz wywołanie funkcji rekurencyjnej jako drugi argumentsetdefault
, nie uzyskasz żadnej wydajności, ponieważ Python zawsze będzie wywoływał funkcję rekurencyjnie.Odkąd wspomniano o zapamiętywaniu, lepszą alternatywą jest użycie dekoratora funkools.lru_cache, jeśli rozważasz ulepszenie funkcji za pomocą zapamiętywania. lru_cache lepiej obsługuje wymagania buforowania dla funkcji rekurencyjnej.
źródło
Jak powiedział Mahomet, są sytuacje, w których tylko czasami chcesz ustawić wartość domyślną. Świetnym przykładem tego jest struktura danych, która jest najpierw wypełniana, a następnie odpytywana.
Zastanów się. Podczas dodawania słowa, jeśli podwęzeł jest potrzebny, ale nie jest obecny, należy go utworzyć, aby rozszerzyć trie. Podczas zapytania o obecność słowa brakujący podwęzeł wskazuje, że słowo nie jest obecne i nie należy go tworzyć.
Defaultdict nie może tego zrobić. Zamiast tego należy użyć zwykłego dykta z metodami get i setdefault.
źródło
Teoretycznie
setdefault
byłoby to przydatne, jeśli czasami chcesz ustawić wartość domyślną, a czasem nie. W prawdziwym życiu nie spotkałem się z takim przypadkiem użycia.Interesujący przypadek użycia pochodzi jednak ze standardowej biblioteki (Python 2.6, _threadinglocal.py):
Powiedziałbym, że używanie
__dict__.setdefault
jest bardzo przydatnym przypadkiem.Edycja : Tak się składa, że jest to jedyny przykład w standardowej bibliotece i jest on w komentarzu. Być może nie jest to wystarczające uzasadnienie istnienia
setdefault
. Oto wyjaśnienie:Obiekty przechowują swoje atrybuty w
__dict__
atrybucie. Tak się składa, że__dict__
atrybut można zapisać w dowolnym momencie po utworzeniu obiektu. Jest to także słownik, a niedefaultdict
. Nie jest rozsądne, aby przedmioty w ogólnym przypadku miały__dict__
jako takie,defaultdict
ponieważ spowodowałoby to, że każdy obiekt posiadałby wszystkie prawne identyfikatory jako atrybuty. Nie mogę więc przewidzieć żadnych zmian w__dict__.setdefault
usuwaniu obiektów Pythona , oprócz całkowitego ich usunięcia, jeśli uznano to za nieprzydatne.źródło
__dict__
jest to implementacja adict
nie adefaultdict
.setdefault
pozostaniu w Pythonie, ale ciekawie jest, że teraz jest prawie bezużyteczne.setdefault
wyraźnie zaznacza, że przypisujesz dyktowi klucz, który może istnieć lub nie, a jeśli nie istnieje, chcesz go utworzyć z wartością domyślną: na przykładd.setdefault(key,[]).append(value)
. Gdzie indziej w programie robisz to,alist=d[k]
gdzie obliczane jest k, i chcesz, aby wyjątek został zgłoszony, jeśli k nie jest w d (co przy domyślnym słowie może wymagać,assert k in d
a nawetif not ( k in d): raise KeyError
Wadą metody
defaultdict
overdict
(dict.setdefault
) jest to, żedefaultdict
obiekt tworzy nowy element ZA KAŻDYM nieistniejącym kluczem (np. Za pomocą==
,print
). Równieżdefaultdict
klasa jest na ogół znacznie mniej powszechna niżdict
klasa, trudniej jest serializować go jako edytor IME.Funkcje PS IMO | metody nieprzeznaczone do mutowania obiektu, nie powinny mutować obiektu.
źródło
defaultdict(lambda l=[]: l)
.Oto kilka przykładów setdefault, które pokazują jego przydatność:
źródło
Przepisałem zaakceptowaną odpowiedź i ułatwiłem ją początkującym.
Dodatkowo podzieliłem metody na kategorie:
źródło
Często używam setdefault, gdy otrzymuję to, ustawiając domyślne (!!!) w słowniku; dość często słownik os.environ:
Mniej zwięźle wygląda to tak:
Warto zauważyć, że można również użyć wynikowej zmiennej:
Ale jest to mniej konieczne niż przedtem, zanim pojawiły się nakazy domyślne.
źródło
Kolejny przypadek użycia, który nie wydaje mi się wspomniany powyżej. Czasami przechowujesz pamięć podręczną obiektów według ich identyfikatora, w którym główna instancja znajduje się w pamięci podręcznej, i chcesz ustawić pamięć podręczną, gdy brakuje.
Jest to przydatne, gdy zawsze chcesz zachować jedną instancję dla odrębnego identyfikatora, bez względu na to, jak za każdym razem uzyskujesz obiekt obj. Na przykład, gdy atrybuty obiektu są aktualizowane w pamięci, a zapisywanie w pamięci jest odraczane.
źródło
Jeden bardzo ważny przypadek użycia, przez który właśnie natknąłem się:
dict.setdefault()
jest świetny do wielowątkowego kodu, gdy potrzebujesz tylko jednego obiektu kanonicznego (w przeciwieństwie do wielu obiektów, które są równe).Na przykład
(Int)Flag
Enum w Pythonie 3.6.0 ma błąd : jeśli wiele wątków konkuruje o element złożony(Int)Flag
, może być więcej niż jeden:Rozwiązaniem jest użycie
setdefault()
jako ostatniego kroku zapisywania obliczonego elementu kompozytowego - jeśli inny został już zapisany, wówczas jest on używany zamiast nowego, gwarantując unikalne elementy Enum.źródło
[Edytuj] Bardzo źle! Setdefault zawsze wyzwalałby długie obliczenia, a Python był chętny.
Rozwijanie odpowiedzi Tuttle'a. Dla mnie najlepszym przypadkiem użycia jest mechanizm pamięci podręcznej. Zamiast:
który zużywa 3 linie i 2 lub 3 odnośniki,
chętnie napisałbym:źródło
long_computation(x)
wywoływana jest tylko wtedy, gdyx not in memo
. Natomiast w drugimlong_computation(x)
zawsze jest nazywany. Tylko przypisanie jest warunkowe, równoważny kodsetdefault
wyglądałby tak:v = long_computation(x)
/if x not in memo:
/memo[x] = v
.Podoba mi się odpowiedź podana tutaj:
http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html
Krótko mówiąc, decyzja (w aplikacjach niekrytycznych pod względem wydajności) powinna być podejmowana na podstawie tego, jak chcesz obsługiwać wyszukiwanie pustych kluczy w dół ( tj. W
KeyError
porównaniu z wartością domyślną).źródło
Innym przypadkiem użycia
setdefault()
jest sytuacja, gdy nie chcesz zastępować wartości już ustawionego klucza.defaultdict
nadpisuje, podczas gdysetdefault()
nie. W przypadku zagnieżdżonych słowników częściej zdarza się, że chcesz ustawić wartość domyślną tylko wtedy, gdy klucz nie jest jeszcze ustawiony, ponieważ nie chcesz usuwać obecnego słownika podrzędnego. To jest, kiedy używaszsetdefault()
.Przykład z
defaultdict
:setdefault
nie zastępuje:źródło