Jak zainicjować słownik pustych list w Pythonie?


88

Moja próba programowego utworzenia słownika list nie pozwala mi na indywidualne adresowanie kluczy słownika. Za każdym razem, gdy tworzę słownik list i próbuję dołączyć do jednego klucza, wszystkie z nich są aktualizowane. Oto bardzo prosty przypadek testowy:

data = {}
data = data.fromkeys(range(2),[])
data[1].append('hello')
print data

Aktualny rezultat: {0: ['hello'], 1: ['hello']}

Spodziewany wynik: {0: [], 1: ['hello']}

Oto, co działa

data = {0:[],1:[]}
data[1].append('hello')
print data

Rzeczywisty i oczekiwany wynik: {0: [], 1: ['hello']}

Dlaczego fromkeysmetoda nie działa zgodnie z oczekiwaniami?

Odpowiedzi:


111

Przekazanie []jako drugiego argumentu do dict.fromkeys()daje raczej bezużyteczny wynik - wszystkie wartości w słowniku będą tym samym obiektem listy.

W Pythonie 2.7 lub nowszym możesz zamiast tego użyć słownika:

data = {k: [] for k in range(2)}

We wcześniejszych wersjach Pythona można używać

data = dict((k, []) for k in range(2))

3
Cóż, jest to raczej nieintuicyjne zachowanie, jakikolwiek pomysł, dlaczego ten sam obiekt jest używany dla wszystkich kluczy?
Bar

2
@Bar Ponieważ nie ma nic innego, co funkcja mogłaby zrobić w ramach semantyki języka Python. Przekazujesz pojedynczy obiekt, który ma być użyty jako wartość dla wszystkich kluczy, tak aby jeden obiekt był używany dla wszystkich kluczy. Byłoby lepiej, gdyby fromkeys()metoda zamiast tego akceptowała funkcję fabryczną, więc moglibyśmy przekazać ją listjako funkcję, a ta funciton byłaby wywoływana raz dla każdego utworzonego klucza, ale to nie jest rzeczywisty interfejs API programu dict.fromkeys().
Sven Marnach

3
To wcale nie jest intuicyjne. Znalezienie tego zajęło mi godzinę. Dzięki
Astrid

1
To samo dzieje się, jeśli przekażesz dict () jako drugi argument. Bardzo zaskakujące zachowanie.
Orly

@Orly Dzieje się tak, ponieważ najpierw tworzony jest jeden pusty słownik, a następnie odniesienie do niego jest przekazywane do wszystkich inicjalizacji.
Dr_Zaszuś

83

Zamiast tego użyj defaultdict :

from collections import defaultdict
data = defaultdict(list)
data[1].append('hello')

W ten sposób nie musisz wcześniej inicjalizować wszystkich kluczy, których chcesz użyć na listach.

W Twoim przykładzie jest używana jedna (zmienna) lista:

alist = [1]
data = dict.fromkeys(range(2), alist)
alist.append(2)
print data

wyjdzie {0: [1, 2], 1: [1, 2]}.


2
W moim przypadku muszę wcześniej zainicjować wszystkie klucze, aby reszta logiki programu działała zgodnie z oczekiwaniami, ale w przeciwnym razie byłoby to dobre rozwiązanie. Dzięki.
Martin Burch,

Wydaje mi się, że w tej odpowiedzi brakuje stwierdzenia, że ​​to rozwiązanie działa, w przeciwieństwie do rozwiązania z OP, ponieważ listtutaj nie jest pusta lista, ale typ (lub myślę, że można to zobaczyć jako konstruktor wywoływalny). Dlatego za każdym razem, gdy przekazywany jest brakujący klucz, tworzona jest nowa lista zamiast ponownego używania tej samej.
Dr_Zaszuś

8

Zapełniasz swoje słowniki odwołaniami do pojedynczej listy, więc po jej zaktualizowaniu aktualizacja jest odzwierciedlana we wszystkich odniesieniach. Zamiast tego spróbuj rozumieć ze słownika. Zobacz Tworzenie słownika ze zrozumieniem list w Pythonie

d = {k : v for k in blah blah blah}

świetna sugestia dotycząca inicjalizacji wartości słownikowych ... dzięki cobie! Rozszerzyłem twój przykład, aby zresetować wartości w istniejącym słowniku, d. Wykonałem to w następujący sposób: d = {k: 0 for k in d}
John

Co jest vw tej odpowiedzi?
Dr_Zaszuś

-2

Możesz użyć tego:

data[:1] = ['hello']

2
Operatorowi operacyjnemu może pomóc wyjaśnienie, dlaczego to działa. Oryginalne pytanie dotyczyło tego, dlaczego nie działa zgodnie z oczekiwaniami.
william.taylor 09

@ william.taylor.09 To trochę oczywiste, dlaczego to działa, prawda?
Conner Dassen

OP pyta (było) „Dlaczego metoda fromkeys nie działa zgodnie z oczekiwaniami?”
william.taylor 09
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.