25 października 2020

Python dictionary FUN

Co to jest dict?

Typ dict (słownik) nie jest już prymitywnym typem danych. Na początku może wydawać się enigmatyczny, natomiast w praktyce jest świetny do pracy z kodem. Dodatkowo cały python oparty jest o słowniki, co za tym idzie 👉 warto z nich korzystać 🙂
Sam słownik to mapa kluczy: wartości. Wartości przechowywane w słowniku posiadają swoje klucze (unikalne). Czyli mogę sobie zdefiniować np. słownik dla państw. Kluczami będą dwu-literowe kody, natomiast wartościamy pełne nazwy.

countries = {
  'PL': 'Poland',
  'EN': 'England',
  'FR': 'France'
}

Słownik definiujemy w klamrach a.k.a curly brackets. Elementy słownika oddzielamy przecinkami, natomiast klucze i wartości (key: value) dwukropkiem. Jeśli znasz taki format danych jak JSON to wygląda bardzo znajomo prawda? Ale o tym później 😉.

Pusty słownik możemy zadeklarować na dwa sposoby.

# curly brackets
mydict = {}
# jako instancja typu dict
myotherdict = dict()

Klucz zawsze jest string'iem, natomiast wartość może być dowolnego typu (np str, int, bool itd albo kolejnym słownikiem). Ogólnie dowolnym typem danych.

jimmy = {
  'first_name': 'jim',
  'last_name': 'choo',
  'age': 33,
  'address': {
    'street': 'sezamee street',
    'building': 999
  }
}

Fun stuff 👌 Jak widać słownik może przechowywać zarówno płaskie jak i zagnieżdzone struktury.

Operacje na słowniku

OK fajnie to wygląda, ale jak takim słownikiem operować? Na szczęście dict ma proste i łatwe do zapamiętania API.

Odczyt po kluczu

Podstawowym sposobem odczytania danych jest podanie klucza w nawiasach kwadratowych.

print(jimmy['last_name'])
'choo'
# możesz zagnieżdżać klucze jeśli wartość jest kolejnym słownikiem
print(jimmy['address']['street'])
'sezamee street'

Jeśli podamy niepoprawny klucz otrzymamy KeyError.

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

Odczyt z użyciem metody get

print(jimmy.get('last_name'))
'choo'

Jeśli nie jesteśmy pewni, czy słownik posiada dany klucz, jako drugi parametr do get możemy podać wartość, która ma być zwrócona jeśli klucz nie zostanie znaleziony.

print(jimmy.get('height', 180))
180

Pozwala to uniknąć zbędnej obsługi błędów w naszym programie, jeśli np możemy przyjąć jakąś domyślną wartość 🖖.

Dodanie nowego klucza: wartości

Analogicznie do odczytu używamy nawiasów kwadratowych.

jimmy['birthdate'] = '01-01-1999'
print(jimmy['birthdate'])
'01-01-1999'

Musisz pamiętać, że jeśli klucz już istnieje to wartość zostanie nadpisana. Czyli nadpisywanie wartości po kluczu odbywa się identycznie jak dodawanie nowych.

Usunięcie klucza (wraz z wartością)

Możesz zdjąć element ze słownika metodą pop.

jimmys_age = jimmy.pop('age')
print(jimmys_age)
33

# słownik nie ma już klucza 'age'
jimmy['age']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'age'

Ewentualnie poprostu usunąć.

del jimmy['first_name']
print(jimmy['first_name'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'first_name'

Klucze

Klucze możesz odczytać za pomocą metody keys.

print(jimmy.keys())
dict_keys(['last_name', 'address', 'birthdate'])

Co za tym idzie możesz w prosty sposób sprawdzić czy słownik posiada klucz.

print('birthdate'in jimmy.keys())
True
print('hobby'in jimmy.keys())
False

Elementy

Elementy słownika możesz odczytac za pomocą metody items.

print(jimmy.items())
dict_items([('last_name', 'choo'), ('address', {'street': 'sezamee street', 'building': 999}), ('birthdate', '01-01-1999')])

Możesz w bardzo prosty sposób iterować się po elementach słownika.

for key, value in jimmy.items():
    print(f'{key} -> {value}')
last_name -> choo
address -> {'street': 'sezamee street', 'building': 999}
birthdate -> 01-01-1999

Z racji tego, że element słownika to tuple'a z dwoma elementami, możemy je od razu rozpakować do dwóch zmiennych w pętli for. Cool 🙂.

Złączenie (merge'owanie) słowników

Możesz łączyć słowniki ze sobą. Najprostszy sposób to rozpakować dwa słowniki do nowego.

dict_one = {'foo': 1, 'bar': 2}
dict_two = {'baz': 3}
dict_three = {**dict_one, **dict_two}
print(dict_three)
{'foo': 1, 'bar': 2, 'baz': 3}

🧠 Jeśli słowniki posiadają te same klucze, wtedy wartości 'z prawej' nadpisują wartości 'z lewej'.

dict_one = {'foo': 1, 'bar': 2}
dict_two = {'baz': 3, 'bar': 4}
dict_three = {**dict_one, **dict_two}
print(dict_three)
{'foo': 1, 'bar': 4, 'baz': 3}

Praktyczne zastosowanie

Python pozwala na przyjemne i zarazem praktyczne zastosowanie słowników. Dodatkowo oszczędzenie sobie ceremoniałów, które często występują w innych, przeważnie statycznie typowanych językach 🙃.

Zapisanie danych z dict'a do JSON'a

Python posiada obsługę dla json w stdlib!

import json

jimmy_json = json.dumps(jimmy)
print(jimmy_json)
{"last_name": "choo", "address": {"street": "sezamee street", "building": 999}, "birthdate": "01-01-1999"}

Odczyt danych z JSON string'a do dict'a

import json

shoes_json = '''
[
  {
    "model": "jordan zeros",
    "size": 12
  },
  {
    "model": "nike shox",
    "size": 10
  }
]
'''
shoes = json.loads(shoes_json)
print(shoes[0].get('model'))
'jordan zeros'

Jak możesz się domyśleć ma to wiele praktycznego zastosowania przy przetwarzaniu danych w JSON (również innych formatów danych) jako słownik. Cool stuff! 🤖

Podsumowanie

Gratulacje! Dzisiaj dowiedziałeś się jak używać słowników oraz stosować je w praktyce do pracy z danymi ☝️ Jeśli intersuje cię bardziej tematyka słowników polecam talk Raymond'a Hettinger'a na temat słowników 👉 Modern Dictionaries by Raymond Hettinger