Python: работа со словарями и задание дефолтных значений
Быстрый ответ
В Python collections.defaultdict автоматически присваивает значение по умолчанию несуществующим ключам, исключая необходимость ручной проверки или использования dict.get().
from collections import defaultdict
# defaultdict работает как товарищ, у которого всегда есть запасная ручка.
my_dict = defaultdict(int)
print(my_dict['нет_ключа'])  # Вывод: 0, и ошибки KeyError нет! 🎉
my_dict['есть_ключ'] = 10
print(my_dict['есть_ключ'])  # Что вы думаете? Вывод: 10. 🙌
defaultdict(int) немедленно предоставит вам инициализированный нулем объект int для любого несуществующего ключа. Это удобно и эффективно.

Эффективное управление отсутствующими ключами
Иногда необходимо обрабатывать отсутствие ключей так, чтобы вернуть альтернативное значение, а не сохранять отсутствующие ключи. В этом случае подходит dict.get(key, default):
my_dict = {'яблоко': 3, 'банан': 2}
# Проверяем наличие вишни. Если её нет, то возвращаем 0🍒
количество = my_dict.get('вишня', 0)
print(количество)  # 0
Если же вам нужно обеспечить инициализацию нескольких отсутствующих ключей, dict.setdefault(key, default) в этом поможет:
my_dict.setdefault('вишня', 0)
print(my_dict['вишня'])  # 0, теперь и вишня тоже в нашем "фруктовом корзине" 🍒
Если требуется установить значения по умолчанию для нескольких ключей, то метод dict.update() позволит объединить текущий словарь с другим, содержащим требуемые значения, при этом не затрагивая уже существующие ключи:
defaults = {'вишня': 0, 'ягода': 0}
my_dict.update({k: defaults[k] for k in defaults if k not in my_dict})
Если на первом месте стоит производительность и отсутствующие ключи встречаются редко, для обработки исключений следует применять try/except, так как этот метод работает быстрее в сравнении с get():
try:
    value = my_dict['груша']
except KeyError:
    value = 0  # Подготовка к изящноому "упадку" 🛡️
Глубинное изучение значений по умолчанию
defaultdict с методами
defaultdict позволяет использовать функцию для генерации нестандартных значений по умолчанию, что делает его поистине универсальным инструментом:
from collections import defaultdict
def default_factory():
    return 'значение по умолчанию'
умный_словарь = defaultdict(default_factory)
print(умный_словарь['несуществующий'])  # 'значение по умолчанию', даже если такого ключа нет!
Таким образом, можно решать разнообразные задачи, в нужный момент обращаясь к функциям задания значений по умолчанию.
Секрет setdefault
setdefault на первый взгляд кажется простым, однако он возвращает значение, что позволяет улучшить эффективность кода:
count = my_dict.setdefault('яблоко', 0)  # Подсчитываем
my_dict['яблоко'] = count + 1            # Обновляем. Всё это в одной строке! 🍏
Сравнение get и __getitem__
dict.get() и dict[key] могут показаться идентичными, однако они работают по-разному. get() никогда не вызывает ошибку и позволяет установить индивидуальное значение по умолчанию, тогда как __getitem__ (или dict[key]) в случае отсутствия ключа вызывает исключение KeyError.
Визуализация
Представьте себе словари Python как почтовое отделение, где письма (значения) доставляются по адресам (ключам). Если адреса не существует (нет такого ключа), на помощь приходит план "Вернуть отправителю" — это и есть значение по умолчанию.
Почтовое Отделение (📬): [Ключ 1, Ключ 2, Ключ 3]
Письмо для Ключа 2: ✉️ -> 📬[Ключ 2]
Что делать с письмом для Ключа 4?: ✉️ -> 🔙 Значение По Умолчанию
В коде это выглядит так:
почтовые_ящики.get('Ключ 4', 'Вернуть отправителю')
Даже при отсутствии ключа, значения не теряются — значение по умолчанию обеспечивает сохранность данных.
| Попытка  | Адрес существует? | Результат                |
| -------- | ------------------ | ------------------------ |
| Ключ 2   | Да                 | Доставлено 📬[Ключ 2]    |
| Ключ 4   | Нет                | Возвращено 🔙 как Значение По Умолчанию |
Таким образом, значение по умолчанию — это своеобразный гарант доставки без задержек и ошибок.
Управление значениями по умолчанию для словарей
Настройка с помощью __missing__
Создав подкласс dict, можно переопределить метод __missing__, контролируя таким образом поведение при обращении к отсутствующим ключам:
class SpecialDict(dict):
    def __missing__(self, key):
        return 'особое значение по умолчанию'
мой_особый_словарь = SpecialDict()
print(мой_особый_словарь['призрак'])  # 'особое значение по умолчанию', всё проходит без проблем!
Это предоставляет возможность настраивать логику и избегать глобальной установки значений по умолчанию.
Вопросы производительности
- Если ключи в словаре в основном существуют, использование try/exceptпредпочтительнее, поскольку опыт показывает, что исключения бывают редкими.
- Если же ключи регулярно отсутствуют, лучше использовать get(), так как этот метод эффективно снижает затраты на обработку исключений.
Будьте осторожны!
- Излишнее использование setdefaultможет внести лишние изменения в словарь. Оно не всегда является лучшим решением.
- Операция update()может перезаписать существующие ключи, что в некоторых случаях нежелательно. Требует аккуратного использования.
Полезные материалы
- Документация Python по методу dict.get()— безопасный доступ к элементам словаря.
- Принцип работы defaultdict — документация по части модуля collections.
- Руководство по использованию defaultdict— правила работы сdefaultdict.
- Сравнение dict.get()иdict[key]— различия между двумя способами доступа к значениям словаря.
- Определение поведения для отсутствующих ключей с __missing__— настройка поведения для несуществующих ключей.
- Основы словарей Python — ключевые особенности и методы словарей Python.


