https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
Słownik (dictionary) to nieuporządkowany zbiór par (klucz: wartość), przy czym klucze muszą być różne. Słowniki nie są sekwencjami, ale odwzorowaniami (mapping). Wartości (obiekty) są przechowywane po kluczu, a nie po ich pozycji względnej.
Klucz musi być niezmienny (immutable), zwykle są to liczby lub stringi. Kluczami mogą być krotki (tuple), jeśli zawierają tylko liczby, napisy i krotki.
Próba pobrania nieistniejącego klucza jest błędem (KeyError).
Słowniki są zmienne, mogą być modyfikowane w miejscu, mogą rosnąć lub kurczyć się na życzenie. Słowniki obsługują zagnieżdżanie obiektów na dowolną głębokość.
Od Pythona 3.7 mamy gwarancję, że klucze w słowniku będą uporządkowane w kolejności ich wstawiania do słownika.
+----------------------+---------------------------+ | Operacja | Znaczenie | +----------------------+---------------------------+ | D = {} ; D = dict() | pusty słownik | | D = {1: "a", 5: "e"} | słownik (dwa klucze) | | len(D) | liczność (liczba par) | | D[key] = value | dodanie pozycji | | D[key] | dostęp do wartości | | D = dict(iterable) | tworzenie z listy par | | D2 = dict(D1) | kopiowanie słownika | | D2 = D1.copy() | stary sposób kopiowania | | D2 = {**D1} | kopiowanie (Py3) | | key in D | zawieranie klucza (bool) | | key not in D | | | D.has_key(key) | dawny sposób (Py2) | | for key in D: pass | iteracja po kluczach | | del D[key] | usuwanie klucza | | D.clear() | czyszczenie słownika | | del D | usuwanie słownika | +----------------------+---------------------------+
D = {} # pusty słownik - inicjalizacja D['one'] = 'jeden' # dodawanie kluczy D['two'] = 'dwa' D['three'] = 'trzy' # Metody słownika bez parametrów. D = {k1:v1, k2:v2, k3:v3} # D = {k1:v1, k2:v2, k3:v3,} # przecinek na końcu jest dozwolony D.keys() # [k1, k2, k3] Py2 D.values() # [v1, v2, v3] Py2 D.items() # [(k1, v1), (k2, v2), (k3, v3)] Py2 D.keys() # zwraca widok kluczy (Py3) D.values() # zwraca widok wartości (Py3) D.items() # zwraca widok par (Py3) # Metody słownika z parametrami. D.has_key('one') # obecnie zalecane: 'one' in D # Kopiowanie słownika (shallow copy). D_alias = D # tylko kopiowanie adresu D_copy1 = D.copy() # metoda słowników do kopiowania D_copy2 = dict(D) # najprostszy sposób id(D), id(D_alias), id(D_cp), id(D_cp2) # Usuwanie elementu ze słownika. del D['two'] # Konwersja listy krotek do dict. D = dict([("a", 1), ("b", 2), ("c", 3), ("d", 4)]) # Ciekawa pętla po parach - items(). for (char, number) in D.items(): print("key: {} value: {}".format(char, number))
Sortowanie kluczy dla słowników.
chars = {} # inicjalizacja pustego słownika # chars.get(char) zwraca chars[char] lub None. # chars.get(char, 0) zwraca chars[char] lub 0. for char in "abrakadabra": chars[char] = chars.get(char, 0) + 1 print(chars) # Sortowanie par (key, value). items = chars.items() # dostaję listę krotek (Py2) items.sort() # Sortowanie samych kluczy. keys = chars.keys() keys.sort() [chars[key] for key in keys] # lista wartości # Python 2.5 zawiera wbudowaną funkcję sorted(), która dla obiektu # iterowalnego zwraca posortowaną listę. for key in sorted(chars): print("{} {}".format(key, chars[key]))
Wybrane metody dla słowników.
# Przykładowe inicjalizacje słownika. D = {k1:v1, k2:v2} # klasyczna D = dict([(k1, v1), (k2, v2)]) # z listy krotek D = dict(zip([k1, k2], [v1, v2])) # z dwóch list D = dict(name1=v1, name2=v2) # {'name1':v1, 'name2':v2} if D != {}: # porównywanie z pustym słownikiem print("słownik nie jest pusty") if D: # pusty słownik oznacza False print("słownik nie jest pusty") # jw D.clear() # wyczyszczenie słownika E = D.copy() # kopia słownika E = dict(D) # jw, ale wygodniej D.has_key(key) # zwraca True/False key in D # jw, zalecane D.items() # zwraca listę krotek (key, value) (Py2) D.keys() # zwraca listę kluczy (Py2) D.values() # zwraca listę wartości (Py2) D.get(key) # zwraca D[key] lub None D.get(key, value) # zwraca D[key] lub value D.setdefault(key, value) # if key in D then return D[key], # if key not in D then set D[key] = value and return value D.pop(key) # zwraca D[key] i usuwa ze słownika D.pop(key, value) # zwraca D[key] lub value, gdy key nie ma w słowniku D.popitem() # zwraca 2-tuple (key, value) [chyba losowo] # lub Error, gdy słownik jest pusty D = dict.fromkeys(S[, value]) # S to sekwencja, value to domyślnie None D = dict.fromkeys(range(4), 0) # {0: 0, 1: 0, 2: 0, 3: 0} D = dict.fromkeys("abc", 1) # {'a': 1, 'c': 1, 'b': 1} D.update(E) # E to dict, czyli for k in E: D[k] = E[k] D.update(**E) # E to dict, jw D.update(F) # F=[("x",10),("y",20)], czyli for (k,v) in F: D[k] = v D.update(name1=value1, name2=value2) # inaczej D.update({'name1': value1, 'name2': value2})
Problem sklejania dwóch słowników.
# http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single-expression?rq=1 # Dane są slowniki A i B. Utworzyć C jako sumę słowników. C = A.copy() C.update(B) # Można utworzyć specjalną funkcję (zalecane rozwiązanie). def merge_dict(a, b): c = a.copy() c.update(b) return c # Użycie: C = merge_dict(A, B) # Uogólnienie działa w Py2 i Py3. 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 = dict() for d in dict_args: result.update(d) return result
locals() zwraca słownik zawierający current scope's local variables, czyli lokalnie dostępne nazwy.
vars() jest równoważne locals().
vars([object]) jest równoważne object.__dict__, czyli dostajemy słownik będący przestrzenią nazw obiektu, zawierającą np. atrybuty obiektu.
Od Pythona 2.5 w klasie dziedziczonej z dict można zdefiniować metodę __missing__(). Wtedy przy wywołaniu D[key], jeżeli klucz nie istnieje, to wywoływana jest metoda __missing__(key). Można określić pożądane zachowanie, np. inne niż stała domyślna wartość. Daje to większą elastyczność niż metody get() czy setdefault().
Metody słowników zwracają iteratory, a nie gotowe listy. Jeżeli chcemy zobaczyć gotową listę trzeba użyć konwersji.
list(D.items()) # zwraca listę krotek (key, value) list(D.keys()) # zwraca listę kluczy list(D.values()) # zwraca listę wartości
Obiekty zwracane przez metody słowników są dynamiczne, to są widoki (views). Można po nich iterować, można sprawdzać należenie do obiektu (membership test).
>>> D = { "first" : 1, "second" : 2 } >>> ks = D.keys() >>> ks dict_keys(['second', 'first']) >>> D["third"] = 3 >>> ks dict_keys(['second', 'third', 'first']) # widać zmianę >>> 'second' in ks # membership test True
Nie ma metody D.has_key(key), stosuje się konstrukcję 'key in D'.
Występuje konstrukcja słowników składanych (dict comprehension). Wydaje się, że można to łatwo zastąpić przez konstrukcję z listą par (key, value),
keys = [k1, k2, k3] values = [v1, v2, v3] D = dict(zip(keys, values)) # Py2 i Py3 D = {k: v for (k, v) in zip(keys, values)} # Py3 i Py2.7 D = {x: x**2 for x in range(9)} # Py3 i Py2.7 D = dict((x, x**2) for x in range(9)) # generator D = {x: x*3 for x in "qwerty"} # Py3 i Py2.7 D = dict((x, x*3) for x in "qwerty") # generator
# Korzystanie z operatora ** (Py3). # Ta sama idea dla argumentów funkcji (**keywords). D1 = {"a": 1, "b": 2} D2 = {"c": 3, "d": 4} merged_dict = {**D1, **D2} # unpacking in a single line print(merged_dict) # {"a": 1, "b": 2, "c": 3, "d": 4} # Problem: merged_dict to zawsze podstawowy słownik, a D1 i D2 # mogą być podklasami słowników, np. defaultdict! # Dawny sposób. merged_dict = {} merged_dict.update(D1) merged_dict.update(D2)
# PEP 584 -- Add Union Operators To dict # Dodanie operatorów '|' i '|=', tak jak dla list. D3 = D1 | D2 # unia słowników tworzy nowy słownik (Py3.9.7) # UWAGA Jeżeli ten sam klucz jest w D1 i D2, to wygrywa D2. # Ogólnie D1 | D2 to nie to samo, co D2 | D1. D1 |= D2 # działa jak D1.update(D2), in-place (augmented assignment) # Przypomnienie: dla list mamy L1 += L2, co działa jak L1.extend(L2), in-place