Як і коли слід використовувати Defaultdict у Python?

У цій статті ви ознайомитеся з тим, як застосовувати defaultdict з модуля колекцій Python для покращення обробки помилок KeyError під час роботи зі словниками.

У Python словник є ефективною вбудованою структурою даних, що зберігає інформацію у вигляді пар ключ-значення. Ключі використовуються для доступу до відповідних значень у словнику.

Проте, якщо у вашому коді Python є кілька словників, які змінюються в процесі виконання, ви часто можете натрапити на помилки KeyError. Існує декілька способів їх уникнення.

У цьому матеріалі ви дізнаєтеся:

  • Що таке KeyError та чому вони виникають.
  • Як обробляти помилки KeyError.
  • Як використовувати defaultdict у Python, який є підкласом, що наслідує вбудований клас dict, для більш ефективної обробки відсутніх ключів.

Розпочнімо!

Що таке помилки KeyError в Python?

При створенні словника в Python необхідно враховувати наступне:

  • Ключі повинні бути унікальними, тобто не повинно бути повторень.
  • При використанні існуючого ітератора як ключів словника, краще використовувати незмінні колекції, наприклад, кортеж.

Отже, ключ вважається дійсним тільки за умови його наявності у словнику, інакше виникає KeyError.

Розгляньмо словник `books_authors`, де ключами є назви книг, а значеннями – імена їх авторів.

Ви можете працювати з кодом паралельно з цим посібником в Python REPL.

books_authors = {
    'Deep Work':'Cal Newport',
    'Hyperfocus':'Chris Bailey',
    'Pivot':'Jenny Blake',
    'The Happiness Equation':'Neil Pasricha'
}

Ви можете скористатися ключем (назвою книги), щоб отримати ім’я автора.

books_authors['Hyperfocus']
'Chris Bailey'

Для доступу до всіх пар ключ-значення у словнику, викличте метод `items()` для об’єкта словника:

for book,author in books_authors.items():
  print(f"'{book}' by {author}")
'Deep Work' by Cal Newport
'Hyperfocus' by Chris Bailey
'Pivot' by Jenny Blake
'The Happiness Equation' by Neil Pasricha

При спробі отримати доступ до значення ключа, відсутнього у словнику, інтерпретатор Python згенерує помилку KeyError. KeyError виникає, коли намагаємося отримати доступ до значень за неіснуючими ключами, такими як “Grit” та “non-existent key”.

books_authors['Grit']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-6-e1a4486f5ced> in <module>
----> 1 books_authors['Grit']

KeyError: 'Grit'
books_authors['non-existent-key']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-a3efd56f69e5> in <module>
----> 1 books_authors['non-existent-key']

KeyError: 'non-existent-key'

Як же обробляти помилки KeyError у Python?

Існує кілька способів, які ми розглянемо у наступному розділі.

Як обробляти KeyError у Python

Розглянемо способи обробки KeyError за допомогою:

  • Умовних операторів if-else.
  • Блоків try-except.
  • Методу словника `.get()`.

#1. Використання умовних операторів If-Else

Найпростішим способом обробки KeyErrors у Python є використання умовних операторів if-else.

Загальний синтаксис операторів if-else у Python:

 if condition:
 	# виконується цей код
 else:
    # виконується інший код 
  • Якщо умова має значення True, виконуються оператори в блоці `if`.
  • Якщо умова має значення False, виконуються оператори в блоці `else`.

У цьому прикладі умовою є перевірка наявності ключа у словнику.

Якщо ключ присутній, оператор `in` поверне True, виконається блок `if`, і виведеться відповідне значення.

key = 'The Happiness Equation'
if key in books_authors:
  print(books_authors[key])
else:
  print('Вибачте, такий ключ не існує!')

# Вивід
# Neil Pasricha

Якщо ключ відсутній у словнику, оператор `in` поверне False, і виконається блок `else`, виводячи повідомлення про відсутність ключа.

key = 'non-existent-key'
if key in books_authors:
  print(books_authors[key])
else:
  print('Вибачте, такий ключ не існує!')

# Вивід
# Вибачте, такий ключ не існує!

#2. Використання операторів Try-Except

Іншим поширеним способом обробки KeyError є використання операторів try-except у Python.

Розгляньте наступний блок коду:

key = 'non-existent-key'
try:
  print(books_authors[key])
except KeyError:
  print('Вибачте, такий ключ не існує!')
  • Блок `try` намагається отримати значення, відповідне заданому ключу.
  • Якщо ключ відсутній, інтерпретатор згенерує KeyError, який буде оброблено як виняток у блоці `except`.

#3. Використання методу `.get()`

У Python для обробки відсутніх ключів можна використовувати вбудований метод словника `.get()`.

Загальний синтаксис використання методу `get()`: `dict.get(key, default_value)`, де `dict` – це дійсний об’єкт словника у Python.

– Якщо ключ присутній у словнику, метод `get()` повертає відповідне значення.
– Інакше повертається значення за замовчуванням.

У цьому прикладі ключі є списком ключів, значення яких ми хочемо отримати. Ми перебираємо список ключів для отримання відповідних значень зі словника `books_authors`.

Тут ми використали метод `.get()` зі значенням за замовчуванням “Не існує”.

keys = ['Grit','Hyperfocus','Make Time','Deep Work']
for key in keys:
  print(books_authors.get(key,'Не існує'))

У наведеному вище коді:

  • Для ключів, що присутні у словнику `books_authors`, метод `.get()` повертає відповідні значення.
  • Коли ключ не існує, як у випадках “Grit” і “Make Time”, метод `.get()` повертає значення за замовчуванням “Не існує”.
# Вивід

Не існує
Chris Bailey
Не існує
Cal Newport

Всі вищенаведені методи допомагають нам у вирішенні помилок, пов’язаних з ключами. Однак, вони є досить об’ємними і вимагають від нас явного оброблення відсутніх ключів. Цей процес можна спростити, використовуючи `defaultdict` замість звичайного словника.

Defaultdict у Python

`defaultdict` є підкласом класу словника (`dict`). Він успадковує поведінку звичайного словника Python. Крім того, він має вбудовану підтримку для обробки відсутніх ключів.

`defaultdict` – це контейнерний тип даних, вбудований у стандартну бібліотеку Python, розташований в модулі `collections`.

Тому необхідно імпортувати його у своє робоче середовище:

from collections import defaultdict

Ось загальний синтаксис використання `defaultdict`:

defaultdict(default_factory)

Ви можете вказати виклик, такий як `int`, `float`, або `list`, як атрибут `default_factory`. Якщо не вказати значення для `default_factory`, то за замовчуванням його значення буде `None`.

Якщо ключ, який ви шукаєте, відсутній, спрацьовує метод `__missing__()`, що повертає значення за замовчуванням з `default_factory`. Потім це значення за замовчуванням повертається.

Підсумовуючи:

  • У Python `defaultdict` повертає значення за замовчуванням, якщо ключ відсутній.
  • Він також додає цю пару ключ-значення за замовчуванням до словника, який потім можна змінити.

Приклади Python Defaultdict

Розглянемо декілька прикладів, щоб зрозуміти, як працює `defaultdict` у Python.

Defaultdict у Python з цілим значенням за замовчуванням

Спочатку імпортуйте `defaultdict` з модуля `collections`.

from collections import defaultdict
import random

Створимо словник цін за замовчуванням.

prices = defaultdict(int)

Тепер заповнимо словник `prices`, використовуючи елементи списку фруктів як ключі. Значення будуть обрані випадково зі списку `price_list`.

price_list = [10,23,12,19,5]
fruits = ['apple','strawberry','pomegranate','blueberry']

for fruit in fruits:
  prices[fruit] = random.choice(price_list)

Поглянемо на пари ключ-значення у словнику `prices` типу `defaultdict`.

print(prices.items())
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10)])

Аналогічно звичайному словнику Python, ви можете отримати доступ до значень ціни в `defaultdict`, використовуючи ключі:

prices['apple']
# 23

Тепер спробуємо отримати доступ до ціни фрукта, якого немає, наприклад, “апельсина”. Бачимо, що він повертає значення за замовчуванням нуль.

prices['orange']
# 0

Якщо вивести словник на екран, побачимо, що додано новий ключ “orange” зі стандартним цілим значенням нуль.

print(prices.items())
dict_items([('apple', 12), ('blueberry', 19), ('pomegranate', 5), ('strawberry', 10), ('orange', 0)])

Defaultdict у Python зі списком як значенням за замовчуванням

Створимо `students_majors` як `defaultdict` списків. Назви спеціальностей будуть ключами. А значеннями будуть списки студентів, що вивчають кожну спеціальність, наприклад, математику, економіку, інформатику тощо.

from collections import defaultdict
students_majors = defaultdict(list)

При спробі отримати доступ до списку студентів, що відповідає спеціальності “Економіка”, `defaultdict` поверне порожній список, і KeyError не виникне!

students_majors['Economics']
# []

Тепер у нас є порожній список, пов’язаний зі спеціальністю “Економіка”. Ми можемо додавати елементи до цього списку за допомогою методу списку `.append()`.

students_majors['Economics'].append('Alex')

У словнику `students_majors` за замовчуванням створено запис для “Economics”.

print(students_majors)
defaultdict(<class 'list'>, {'Economics': ['Alex']})

Ви можете додати ще студентів до списку, що відповідає спеціальності “Економіка”, додати нову спеціальність і багато іншого!

students_majors['Economics'].append('Bob')
students_majors['Math'].append('Laura')
print(students_majors)
defaultdict(<class 'list'>, {'Economics': ['Alex', 'Bob'], 'Math': ['Laura']})

Висновок

Сподіваюся, ця стаття допомогла вам зрозуміти, як і коли використовувати `defaultdict` у Python. Після виконання прикладів коду, наведених у цьому матеріалі, ви можете використовувати `defaultdict` як бажану структуру даних у своїх проєктах, коли це потрібно.

Ось підсумок того, що ви дізналися у цій статті.

  • Працюючи зі словником Python, ви часто стикаєтеся з помилками KeyError.
  • Для обробки таких KeyError можна використовувати кілька явних методів. Ви можете використовувати умовні оператори, блоки try-except або метод `.get()`. Але тип даних `defaultdict` з модуля `collections` може значно спростити обробку KeyError.
  • Ви можете використовувати `defaultdict(default_factory)`, де `default_factory` є дійсним викликом.
  • Якщо ключ відсутній у `defaultdict`, значення за замовчуванням (отримане з `default_factory`) та ключ додаються до `defaultdict`.

Далі ви можете ознайомитися з навчальним посібником про функцію `map` у Python.