Перевод статьи «How to Use DefaultDict in Python».
На протяжении всего времени работы с наборами данных в Python словарь был моей самой используемой структурой данных. Он универсален и прост в использовании.
Нужно подсчитать количество вхождений символа? Используйте словарь!
Хотите создать список футболистов и связанных с ними статистических данных? Словарь!
Однако они не являются безотказными. Во многих задачах при работе с данными вы сталкиваетесь с большим количеством ошибок KeyErrors, и это может раздражать.
Устранение этих ошибок приводит к появлению нескольких дополнительных строк кода. Это снижает читабельность и повышает сложность. Если вы работаете с большим количеством данных, эта проблема может выйти из-под контроля.
Модуль collections решает эту проблему сложности. Модуль collections — это часть стандартной библиотеки Python, которая содержит несколько замечательных способов работы с данными. Основная цель модуля — сделать ваш код более читабельным и упростить обработку данных с помощью некоторых дополнительных типов.
Я чаще всего использую defaultdict, и сегодня мы рассмотрим несколько простых примеров его применения. Чтобы в полной мере оценить этот контейнер данных, вы должны обладать рабочими знаниями о Python. Точнее, быть знакомым с обычными словарями.
Как упростить код с помощью DefaultDict
Прежде чем мы перейдем к сегодняшней теме, давайте рассмотрим ситуацию. Я хочу создать словарь, который выдавал бы мне количество уникальных букв в слове «Mississippi». Там много букв «s» и «p», и у меня нет времени пересчитывать их вручную.
Вот как я могу это сделать, используя стандартный словарь:
letters = {}
for letter in «Mississippi»:
if letter not in letters:
letters[letter] = 1
else:
letters[letter] +=1
print(letters)
# {‘M’: 1, ‘i’: 4, ‘s’: 4, ‘p’: 2}
Достаточно просто. Эта программа:
Перебирает строку в цикле.
На каждой итерации проверяет, есть ли очередная буква в нашем словаре letters.
Если буква присутствует, к текущему значению ключа добавляется единица.
Если буквы нет в словаре letters, программа добавляет ее в словарь в качестве ключа и устанавливает начальное значение в 1.
Этот пример был довольно простым, но вы уже видите, как усложняется код. Давайте посмотрим, как можно сделать лучше:
from collections import defaultdict
letters = defaultdict(int)
for letter in «Mississippi»:
letters[letter] += 1
print(letters)
# defaultdict(<class ‘int’>, {‘M’: 1, ‘i’: 4, ‘s’: 4, ‘p’: 2})
Как видите, все условные операторы теперь исчезли. Код стало читать немного легче, но в конце программы мы все равно получили тот же результат.
В этом и заключается преимущество defaultdict. Давайте разберем этот контейнер данных подробнее.
Изучение контейнера данных DefaultDict
Идея defaultdict проста: если мы пытаемся получить доступ к значению несуществующего ключа, в словарь добавляется пара ключ-значение с этим ключом и значением, заданным по умолчанию.
В приведенном выше примере мы начали с пустого defaultdict без записей. Для каждой уникальной буквы словарь создал запись. Поскольку в качестве значения по умолчанию мы использовали int, значение созданной записи было равно 0. После создания записи словарь добавил к этому значению единицу.
В конце программы выводится количество букв, причем нам не приходится использовать условия или как-то вмешиваться вручную. Очень питонично.
Как установить значение по умолчанию в DefaultDict
Контейнер данных defaultdict при инициализации принимает один аргумент с именем default_factory.
Этот аргумент default_factory представляет собой функцию. Когда программа пытается получить доступ к несуществующей записи, defaultdict вызывает default_factory без каких-либо аргументов. Так, например, я могу вызвать defaultdict с функцией int() следующим образом:
d1 = defaultdict(int)
Когда я попытаюсь получить доступ к несуществующей записи, функция добавит к этой записи значение функции int, равное 0.
d1 = defaultdict(int)
d1[“Adding an entry!”]
Print(d1)
# defaultdict(<class ‘int’>, {‘Adding an Entry!’: 0})
Изучение возможностей DefaultDict
Теперь, когда вы знаете основные принципы использования defaultdict, мы можем изучить его возможности.
Как я уже говорил, default_factory — это функция без аргументов. Это означает, что мы можем использовать как встроенные типы данных, так и пользовательские функции — при условии, что они не принимают аргументов.
Давайте вернемся к нашему примеру с Mississippi. Я хочу узнать все индексы, под которыми стоят буквы «i». Я собираюсь использовать defaultdict со списком в качестве аргумента default_factory, чтобы мы могли отслеживать все индексы.
from collections import defaultdict
my_word = «Mississippi»
d1 = defaultdict(list)
for index, letter in enumerate(my_word):
if letter == «i»:
d1[letter].append(index)
print(d1)
# defaultdict(<class ‘list’>, {‘i’: [1, 4, 7, 10]})
Потрясающе! Я проверил этот пример вручную, и, похоже, он правильный. Буква i находится под индексами 1, 4, 7 и 10.
Этот пример выглядит немного иначе, но идея все та же. Алгоритм действий следующий:
Создаем defaultdict с аргументом default_factory list.
Перебираем в цикле слово «Mississippi».
Если итерируемая буква равна «i», обращаемся к словарю по ключу «i».
Если такой записи в словаре еще не существует, контейнер данных defaultdict создаст ее и использует в качестве значения пустой список.
Затем с помощью спискового метода append добавляем индекс итерируемой буквы.
Давайте изучим этот вопрос подробнее. Поскольку default_factory принимает функцию в качестве аргумента, мы можем определить свою собственную — при условии, что наша пользовательская функция не принимает аргумент.
from collections import defaultdict
def return_hello():
return «Hello!»
d1 = defaultdict(return_hello)
d1[1]
d1[2]
d1[3]
print(d1)
# defaultdict(<function return_hello at 0x0000014FC5D28DC0>, {1: ‘Hello!’, 2: ‘Hello!’, 3: ‘Hello!’})
Здесь я определил функцию, которая просто возвращает «Hello!», и передал ее в качестве аргумента default_factory. Теперь, когда мы пытаемся получить доступ к несуществующим записям в нашем словаре, defaultdict вызывает мою пользовательскую функцию, чтобы определить значение по умолчанию!
В заключение
В этом руководстве мы рассмотрели defaultdict, который является контейнером данных во встроенном модуле collections из стандартной библиотеки Python. Он позволяет нам получить доступ к несуществующим записям в словаре, создавая их на лету и присваивая значение по умолчанию.
defaultdict принимает аргумент default_factory, указывающий словарю значение по умолчанию, которое следует присвоить ключу. В качестве аргумента могут использоваться встроенные функции, такие как int или list, или пользовательские функции, такие как наша функция return_hello.
Надеюсь, эта статья была вам полезна!
Запись Как использовать DefaultDict в Python впервые появилась techrocks.ru.