Kolejnym niezwykle przydatnym typem danych w Pythonie jest słownik, czyli nieuporządkowana kolekcja obiektów, do których dostęp do odbywa się poprzez klucz. Pozycja elementu w słowniku nie ma zatem najmniejszego znaczenia. Słowniki należy stosować wtedy, gdy nazwę przedmiotów danej kolekcji są ważniejsze od ich pozycji.
Słowniki służą jako mechanizmy wyszukiwania, a ich wysokie zoptymalizowanie sprawia, że są idealnym typem kolekcji do obsługi szybkich operacji wyszukiwania.
Charakterystyka słowników
- Dostęp do elementów jest możliwy poprzez użycie klucza,
- Klucze są symboliczną lokalizacją elementów w słowniku, jako że są one nieuporządkowane,
- Słowniki mają zmienną długość, ich elementy są niejednorodne, a także mogą być dowolnie zagnieżdżone,
- Słowniki są obiektami mutowalnymi, jednak nie obsługują operacji, które opierają się na stałej pozycji elementów, takich jak wycinki czy konkatenacja. Są natomiast jedynym wybudowanym typem, które należy do kategorii odwzorowań, czyli obiektów odwzorowujących klucze na wartości.
- Jako klucze słownik akceptują tylko wartości niemutowalne, takie jak łańcuchy znaków lub liczby.

Najczęściej wykonywane operacje na słownikach
Do najczęściej wykonywanych operacjach na słownikach należy tworzenie słowników, przy czym są tutaj różne możliwości:
Statyczne tworzenie słownika:
D = {'name' : 'Python', 'version': 3.9}
>>> D = dict([('name', 'Python'), ('version', 3.9)])
>>> D
{'name': 'Python', 'version': 3.9}
D1 = dict([('name', 'Python'), ('version', 3.9)])
>>> D1 = dict([('name', 'Python'), ('version', 3.9)])
>>> D1
{'name': 'Python', 'version': 3.9}
>>> D2 = dict.fromkeys(["name", "version"])
>>> D2
{'name': None, 'version': None}
Pobieranie kluczy:
>>> D.keys()
dict_keys(['name', 'version'])
Pobieranie wartości:
>>> D.values()
dict_values(['Python', 3.9])
Pobieranie krotek klucz plus wartość:
>>> D.items()
dict_items([('name', 'Python'), ('version', 3.9)])
Jeśli powyższe wartości chcemy otrzymać w bardziej przystępnym typie danych, to należy przekonwertować je na listę:
>>> list(D.items())
[('name', 'Python'), ('version', 3.9)]
Pobieranie wartości z słownika odbywa się poprzez indeksowanie po kluczu:
>>> D['name']
'Python'
Możliwe jest ustawienie wartości domyślnej, jeśli kluczy nie zostanie znaleziony:
>>> D.get('surname', 'Pythonic')
'Pythonic'
Usuwanie elementu odbywa się poprzez skorzystanie z metody pop(), której również można nadać wartości domyślną, aby uniknąć błędu:
>>> D.pop('surname', 'Pythonic')
'Pythonic'
Możemy również wcześniej sprawdzić, czy dany klucz znajduje się w słowniku, wykorzystując przy tym operator zależności in, które działa również na tablicach oraz łańcuchach znaków.
>>> 'version' in D
True
Dodawanie nowego elementu do słownika jest bardzo proste, wystarczy podać klucz oraz jego nową wartość:
>>> D['surname'] = 'Pythonic'
>>> D
{'version': 3.9, 'surname': 'Pythonic'}
Żeby usunąć element po kluczu, należy skorzystać z instrukcji del:
>>> del D['surname']
D {'version': 3.9}
Przypisanie elementu do istniejącego indeksu (klucza) zmienia jego wartość.
Dlaczego w celu pobrania wartości słownika najlepiej korzystać z metody get()? Ponieważ w razie, gdy dany słownik nie zawiera wybranego wpisu, wówczas operacja zwróci wynik None, a nie błąd:
>>> print(D.get('surprise'))
None
>>> D['surprise']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'surprise'
Jak połączyć dwa słowniki?
Zeby połączyć ze sobą dwa słowniki w Pythonie można skorzystać z metody update() (nadpisuje ona jednak wartości z dodawanego słownika).
>>> D1 = dict([('name', 'Python'), ('version', 3.9)])
>>> D2 = {"version":2.7}
>>> D1.update(D2)
>>> D1
{'name': 'Python', 'version': 2.7}
Jak przeszukiwać słowniki po wartościach?
Przeszukiwanie słowników po kluczu jest łatwe, wystarczy po prostu podać nazwę klucza jako indeks. Natomiast wyszukiwanie po wartości wymaga nieco więcej kodu. W tym celu można na przykład skorzystać z metody items(), która po opakowaniu w funkcję list() tworzy listę krotek składających się z klucza i wartości. Następnie należy dokonać przeszukania za pomocą pętli for pamiętając o tym, aby zmienna służąca do iterowania miała formę odpowiadającą formie elementów w liście, a więc dwuelementową krotkę:
>>> value_list = list(D1.items())
>>> value_list
[('name', 'Python'), ('version', 2.7)]
>>> for (key, value) in value_list:
... if value == 'Python':
... print(key)
...
name
Działa to również wtedy, gdy więcej niż jeden klucz ma określoną wartość:
>>> D1['reptile'] = "Python"
>>> value_list = list(D1.items())
>>> for (key, value) in value_list:
... if value == 'Python':
... print(key)
...
name
reptile
Kilka uwag na temat korzystania ze słowników
Słowniki mogą służyć jako elastyczne listy, w których liczby całkowite służą jako klucze. Dlaczego warto stosować tego typu strukturę? Używając list, nie możemy przypisać elementu do pozycji przesunięcia, która znajduje się poza końcem tej listy, czyli jest większa od długości listy. Przykładowo do pustej listy nie możemy dodać żadnego elementu na pozycji „większej „dalszej” niż 0. Jest to tymczasem jak najbardziej możliwe w przypadku słowników, gdzie liczba będzie po prostu kluczem, a w słownik ulegnie automatycznemu rozszerzeniu.
>>> L = []
>>> L[10] = 'iii'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> L = {}
>>> L[10] = 'iii'
>>> L
{10: 'iii'}
Słowniki są ponadto wykorzystywane do implementacji tak zwanych rzadkich struktur, a więc na przykład tablic wielowymiarowych, gdzie tylko kilka pozycji zawiera określoną wartość:
>>> matrix = {}
>>> matrix [(1, 2, 3)] = 6
>>> matrix[(4, 5, 6)] = 15
Słowniki mogą również imitować bazy danych, w których do określonych rekordów dodajemy nowe obiekty:
>>> rec = {}
>>> rec['name'] = 'Python'
>>> rec['versions'] = {'this_version': 3.9, 'previous_version' : 2.7}
>>> rec
{'name': 'Python', 'versions': {'this_version': 3.9, 'previous_version': 2.7}}
Takie rekordy możemy dodawać do listy lub słownika:
>>> db = []
>>> db.append(rec)
>>> rec
{'name': 'Python', 'versions': {'this_version': 3.9, 'previous_version': 2.7}}
>>> db
[{'name': 'Python', 'versions': {'this_version': 3.9, 'previous_version': 2.7}}]
>>> db = {}
>>> db['programming_language'] = rec
>>> db
{'programming_language': {'name': 'Python', 'versions': {'this_version': 3.9, 'previous_version': 2.7}}}
Dynamiczne tworzenie słowników
Słowniki można tworzyć dynamicznie na dwa sposoby:
Dodając po jednym wpisie, jak we wcześniejszych przykładach lub korzystając z konstruktora dict(), gdzie argumenty to lista par typu klucz- wartość, najczęściej pobrana z innego miejsca w kodzie:
>>> kv_list=[('first', 1), ('second', 2)]
>>> dict(kv_list)
{'first': 1, 'second': 2}
Jeśli wszystkie klucze w słowniku mają mieć tą samą wartość, warto skorzystać z prostej metody fromkeys(), gdzie klucze są podane jako lista z wartościami, a drugim argumentem jest właśnie wartość.
>>> dict.fromkeys(['a', 'b'], 10)
{'a': 10, 'b': 10}
Tworzenie słowników składanych
Podobnie jak w przypadku list możliwe jest tworzenie słownika składanego. Słownik składany wykorzystuje wewnętrzną pętlę, która z każdej literacji zbiera wyniki wyrażeń dla danej pary klucz-wartość, a następnie dodaje je do słownika. Szablon wygląda następująco:
>>> D = {k: v for (k, v) in zip(('pierwszy', 'drugi'), (1, 2))}
>>> D
{'pierwszy': 1, 'drugi': 2}
Funkcja wbudowana zip() łączy tutaj pierwsze elementy pierwszej krotki z pierwszym elementem drugiej krotki, a następnie to samo robi z drugim elementem. Jeśli zarówno klucz, jak i wartość mają wspólną bazę, a więc na przykład klucz jest liczbą, a wartość jej potęgą, wtedy możliwe jest użycie wspólnego mianownika:
>>> D = {x: x ** 2 for x in [1, 2, 3]}
>>> D
{1: 1, 2: 4, 3: 9}
Dlaczego żeby uzyskać prosty dostęp do wyników funkcji keys(), values() oraz items() należy użyć funkcji list()? Dzieje się tak dlatego, że te trzy obiekty są tak naprawdę obiektami widoków, które są iteratorami, generującymi po jednym elemencie na żądanie. Oznacza to, że wywołując taki obiekt za pomocą wbudowanej metody next() lub iterując po nim w pętli for otrzymujemy po jednym elemencie na każdą iterację. Konwersja obiektu widoku na listę wymusza na obiekcie zwrócenie wszystkich wartości naraz.
>>> list(D.keys())
[1, 2, 3]
>>> list(D.values())
[1, 4, 9]
>>> list(D.items())
[(1, 1), (2, 4), (3, 9)]
Warto dodać, że wyniki tych metod zachowują się jak zbiory, a więc mogą być poddawane takim operacjom jak suma różnica lub iloczyn.
Jak posortować słownik?
Sortowanie słownika jest możliwe na dwa sposoby: poprzez posortowanie listy zawierającej klucze słownika, a następnie wywołanie wartości słownika zgodnie z tymi kluczami lub poprzez skorzystanie z funkcji sorted().
>>> ks = list(D.keys())
>>> for k in ks: print(k, D[k])
...
1 1
2 4
3 9
Funkcja sorted (działa bez potrzeby uzyskiwania widoku kluczy słownika):
>>> for k in sorted(D): print(k, D[k])
...
1 1
2 4
3 9
W następnym wpisie przyjrzymy się krotkom 🙂
Dodaj komentarz
Musisz się zalogować, aby móc dodać komentarz.