Struktury danych w Pythonie #2. Słowniki

Znasz już listy i krotki? Jeśli nie, to zajrzyj do części 1 tej serii. Jeśli tak, to czas poznać kolejną strukturę danych w Pythonie – słownik (dict).

A pomogą nam w tym dobrze znane postaci z dzieciństwa.

POKEMONY! 🤩

Najbardziej w pamięci utkwiły mi imiona dwóch z nich: Pikachu i Charmander. Przyjrzyjmy więc się im bliżej.

Możemy przypisać im kilka atrybutów, takich jak: typ, siła obrony, siła ataku, czy szybkość. Stwórzmy więc małą tabelkę.

PokemonTypAttackDefenseSpeed
Pikachuelectric554090
Charmanderfire524365

Moglibyśmy w kolejnych wierszach dopisywać następne pokemony, ale interesuje nas coś innego. Powyższy sposób opisu charakteryzuje się 3 zasadami:

  • atrybuty nie powtarzają się,
  • kolejność wierszy nie ma znaczenia,
  • możemy zmienić wartości poszczególnych komórek (jeśli wytrenujemy pokemona 😁).

No to teraz zamieńmy tabelkę na kod i opiszmy Pikachu w następujący sposób:

pikachu = {
    'type':'electric',
    'attack':55, 
    'defense':40, 
    'speed': 90
} 

CZYM SĄ SŁOWNIKI?

Wykorzystując nawiasy klamrowe stworzyliśmy zmienną typu słownik (dict). 

Dane podane z lewej strony (‘type’, ‘attack’, ‘defense’, ‘speed’) to klucze (keys), zaś te z prawej (‘electric’, 55, 40, 90) – wartości (values). 

Pomiędzy kluczem a wartością stawiamy dwukropek, zaś poszczególne pary klucz – wartość oddzielamy przecinkiem.

Stwórzmy więc definicję.

Słownik to struktura danych zawierająca elementy w postaci klucz-wartość.
1. Wartości są mutowalne.
2. Klucze nie mogą się powtarzać.
3. Kolejność elementów nie jest zachowana.
4. Wartości mogą być zmiennymi dowolnych typów.

UWAGA! Wartości są mutowalne, ale klucze nie.

Oznacza to, że w każdej chwili możemy zmienić wartość klucza z 90 na 100, ale nie zmienimy nazwy klucza 'speed' na 'velocity'.

OPERACJE NA SŁOWNIKACH

Tworzenie słownika

Do stworzenia słownika możemy wykorzystać jedną z trzech opcji:

  • prosta inicjalizacja zmiennej – nawiasy klamrowe:
>>> pikachu = {'type':'electric', 'attack':55, 'defense':40, 'speed': 90}

# wypiszmy teraz wartość zmiennej
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90}
 
  • funkcja dict():
>>> pikachu = dict({'type':'electric', 'attack':55, 'defense':40, 'speed': 90})

# wypiszmy teraz wartość zmiennej
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90}
 
  • funkcja dict.fromkeys()umożliwia przypisanie jednej wartości wszystkim kluczom:
>>> my_keys = ['x', 'y']
>>> my_values = 0
>>> my_dict = dict.fromkeys(my_keys, my_values)
>>> my_dict
{'x': 0, 'y': 0}

# jeśli nie podamy wartości, wszystkim kluczom przypisany zostanie None
>>> my_second_dict = dict.fromkeys(my_keys)
>>> my_second_dict 
{'x': None, 'y': None} 

Pobieranie elementów

Pobierając wartość wybranego klucza, znowu mamy do dyspozycji dwie możliwości. Możemy wykorzystać nawiasy kwadratowe lub metodę get().

>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90}

# 1. nawiasy kwadratowe
>>> pikachu['type'] 
'electric'

>>> pikachu['typ']      
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'typ'

# 2. metoda get()
>>> pikachu.get('type') 
'electric'
>>> pikachu.get('typ')
None
>>> pikachu.get('type', 'brak')
'brak' 

W przypadku poprawnie podanego klucza, tzn. takiego, który istnieje w słowniku, oba sposoby zwrócą nam to samo, czyli przypisaną wartość.

Problem pojawia się jednak w sytuacji, gdy podamy nieistniejący klucz. Jak widać w powyższym fragmencie kodu, opcja pierwsza wyrzuci wyjątek KeyError i przerwie działanie programu.

I właśnie aby zapobiegać takim sytuacjom stworzona została metoda get(), która domyślnie zwróci None. 

Ale oferuje ona coś jeszcze. Jako jej drugi parametr możemy podać własną domyślną wartość, która zostanie zwrócona w przypadku braku podanego klucza w słowniku

Dzięki temu program będzie działał poprawnie, a my możemy zabezpieczyć się zarówno przed wyjątkiem, jak i (niepożądaną zwykle) wartością None 🥳. 

Dodawanie elementów

Do wcześniej stworzonego słownika w każdej chwili możemy dodać nowy element. Zaktualizujmy więc informacje o Pikachu i dodajmy jego współczynnik zdrowia (HP). W tym momencie znów przydadzą się nawiasy kwadratowe. 

>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90}

>>> pikachu['hp'] = 35
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90, 'hp': 35}
 

Modyfikacja istniejących elementów

Przyjrzyj się jescze raz ostatnio wywołanym liniom kodu. Jak myślisz, co stanie się, jeśli w nawiasach podasz nazwę klucza istniejącego już w słowniku?

Sprawdź swoje przypuszczenia 😉

>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90, 'hp': 35}

>>> pikachu['hp']  = 100
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90, 'hp': 100} 

Czyż to nie proste?
Jeśli w nawiasach kwadratowych podamy nazwę klucza, który już istnieje, zmodyfikujemy przypisaną do niego wartość.

Ale to jeszcze nie wszystko. Python udostępnia też metodę update(), w której możemy podać dowolną ilość kluczy do zmiany.

Spójrz na poniższy kod.

>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90}

>>> pikachu.update({'hp':100, 'speed': 100})
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 100, 'hp': 100} 

Zmodyfikowaliśmy kilka kluczy jedną linią kodu! Piękne, prawda? 😃

To patrz na to!

>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 100, 'hp': 100}

>>> pikachu.update({'hp':999, 'my_favourite': 'Of course!'})
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 100, 'hp': 999, 'my_favourite': 'Of course!'} 

Właśnie dodaliśmy nowy klucz, wykorzystując metodę update().
Nie wiem jak Ty, ale ja już słyszę w głowie tę nutę:
🎶 Pokemooon, czy już wszystkie masz?!  🎶

Ale wróćmy do słowników 🤭.

Usuwanie elementów słownika

Tu znowu mamy do dyspozycji kilka możliwości w zależności od potrzeb.

  • usuwanie elementu po kluczu – pop(key), del:
>>> pikachu
{'type': 'electric', 'attack': 55, 'defense': 40, 'speed': 90, 'hp': 35}

# metoda pop() zwraca i usuwa element o podanym kluczu
>>> pikachu.pop('attack')
55
>>> pikachu
{'type': 'electric', 'defense': 40, 'speed': 90, 'hp': 35}

# metoda del usuwa element o podanym kluczu 
>>> del pikachu['speed']
>>> pikachu
{'type': 'electric', 'defense': 40, 'hp': 35} 
  • usuwanie ostatnio dodanego elementu – popitem():
>>> pikachu
{'type': 'electric', 'defense': 40, 'speed': 90, 'hp': 35}

# metoda popitem() zwraca i usuwa ostatnio dodany element 
>>> pikachu.popitem()
('hp', 35)
>>> pikachu
{'type': 'electric', 'defense': 40, 'speed': 90}
 

Poznaliśmy już podstawowe operacje, czas na kilka bonusów.

WYSZUKIWANIE

Jeśli chcesz sprawdzić, czy klucz istnieje w słowniku, wykorzystaj słowo kluczowe in.

>>> pikachu
{'type': 'electric', 'defense': 40, 'hp': 35}
>>> 'type' in pikachu
True
>>> 'typ' in pikachu
False 

SPRAWDZANIE STRUKTURY SŁOWNIKA

Python umożliwia sprawdzanie i kontrolowanie struktury słownika:

  • wyświetlenie kluczy – keys():
>>> pikachu_keys = pikachu.keys()
>>> pikachu_keys
dict_keys(['type', 'defense', 'hp'])

# jeśli zmodyfikujemy słownik, zmienna przechowująca klucze zostanie zaktualizowana
>>> pikachu['speed'] = 90
>>> pikachu_keys
dict_keys(['type', 'defense', 'hp', 'speed']) 
  • wyświetlenie wartości – values():
>>> pikachu_values = pikachu.values()
>>> pikachu_values
dict_values(['electric', 40, 35, 90])

# jeśli zmodyfikujemy słownik, zmienna przechowująca wartości zostanie zaktualizowana
>>> pikachu['speed'] = 100
>>> pikachu_values
dict_values(['electric', 40, 35, 100]) 
  • wyświetlenie elementów – items():
>>> items = pikachu.items()
>>> items
dict_items([('type', 'electric'), ('defense', 40), ('hp', 35), ('speed', 100)])

# jeśli zmodyfikujemy słownik, zmienna przechowująca elementy zostanie zaktualizowana
>>> pikachu.popitem()
('speed', 100)
>>> items
dict_items([('type', 'electric'), ('defense', 40), ('hp', 35)]) 

ITERACJA PO ELEMENTACH SŁOWNIKA

Wykorzystując powyższe metody, możemy na różne sposoby iterować po elementach słownika.

>>> pikachu
{'speed': 90, 'attack': 55}

# sposób 1: 
# domyślnie for ... in ... iteruje po kluczach słownika
>>> for klucz in pikachu:
...     print(klucz, '-', pikachu[klucz])
... 
speed - 90
attack - 55

# sposób 2: 
# aby sięgnąć bezpośrednio po wartość, użyj metody values()
>>> for wartosc in pikachu.values():
...     wartosc
... 
90
55

# sposób 3:
# aby jednocześnie sięgnąć po klucz i wartość, użyj metody items()
>>> for klucz, wartosc in pikachu.items():
...     print(klucz, '-', wartosc)
... 
speed - 90
attack - 55
 

ZAGNIEŻDZENIA

I na koniec jeszcze jeden przykład elastyczności Pythona. W słowniku możemy trzymać zarówno liczby, stringi, wartości bool, jak też listy, krotki oraz … inne słowniki. Przykładowo naszego Pikachu mogłabym opisać na inne sposoby:

>>> pikachu = {'name': 'Pikachu', 'power': {'attack':55, 'speed': 100}, 'is_yellow': True}
>>> pikachu
{'name': 'Pikachu', 'power': {'attack': 55, 'speed': 100}, 'is_yellow': True}

#Pamiętacie, że pokemony miały też specjalny atak i obronę?
>>> pikachu = {'attacks': [55, 50], 'defenses' : (40, 50)}
>>> pikachu
{'attacks': [55, 50], 'defenses': (40, 50)}

 

CZAS NA ĆWICZENIA

No to teraz czas sprawdzić, czy złapałeś wszystkie Pokemony!

Spróbuj rozwiązać poniższe zadanka i przetestuj swoją wiedzę.

Zadanie 1. Sportowcy
Właśnie zostałeś dziennikarzem sportowym i czeka Cię pierwsze poważne zadanie. Redaktor naczelny wysłał Ci poniższą listę informacji o kilku znanych sportowcach.

Robert, Lewandowski, piłka nożna, mężczyzna, sport zespołowy, 32
Kamil, Stoch, skoki narciarskie, mężczyzna, sport indywidualny. 33
Iga, Świątek, tenis, kobieta, sport indywidualny, 19
Leo Messi, piłka nożna, mężczyzna, sport zespołowy, 33
Łukasz, Kubot, tenis, mężczyzna, sport indywidualny, 38

1. Stwórz zmienne typu słownik opisujące każdego ze sportowców. Skonstruuj je tak, aby zawierały różne typy danych: int, str, bool… Zwróć też uwagę na to, aby zachować identyczne nazewnictwo kluczy we wszystkich zmiennych. Przyda Ci się to w kolejnych zadaniach 😉
2. Stwórz listę wszystkich sportowców.
3. Wykorzystując stworzoną przed chwilą listę sportowców, stwórz nową listę, która będzie zawierała tylko piłkarzy.
4. Stwórz funkcję, która policzy ilu sportowców uprawia sporty indywidualne, a ilu zespołowe, Wypisz te wartości.
5. Uups, redaktor podesłał Ci niepełną listę. Zaktulizuj informacje o sportowcach, dopisując nowy klucz: ‘country’. Zastanów się, jak zrobić to skutecznie.

Rozwiązanie: LINK

 

Zadanie 2. Pokemony
Czas na powrót do dzieciństwa!
Zbieramy Pokemony! Ale one nie wskoczą tak łatwo do pokeballa.
Wykonaj kilka zadań, a będziesz miał je wszystkie ;).

1. Mając zdefinowaną listę pokemonów, oblicz dla każdego z nich pełną moc – Total i wypisz jej wartość. 
Wskazówka: Total jest sumą atrybutów: [‘HP’, ‘Attack’, ‘Defense’, ‘Sp. Atk’, ‘Sp. Def’, ‘Speed’]

2. Stwórz słownik, w którym kluczami będą imiona pokemonów, a wartościami ilość liter przypisanego imienia, np. klucz: ‘Pikachu’ –  wartość: 7. Wypisz zawartość słownika.

 

Rozwiązanie: LINK

 

Specjalnie dla Ciebie przygotowałyśmy zadania o zróżnicowanej trudności na naszym profilu na GithubieLINK. Zadania i ich rozwiązania zostały podzielone na odpowiednie foldery: Listy, Tuple, Słowniki, itd. Przy każdym zadaniu znajdziesz stopień trudności.

Powodzenia w rozwiązywaniu zadań! 

Napotkałeś jakiś problem, masz pytanie? A może przydała Ci się dzisiejsza lekcja? Zostaw komentarz i podziel się z nami swoją opinią.

Miłego dnia!

0 0 vote
Article Rating
guest
0 komentarzy
Inline Feedbacks
View all comments