Пропустить до содержимого

Как использовать defaultdict в Python?

CodeMDD.io

Использование типа defaultdict в Python для работы с отсутствующими ключами

Автор: Леоданис Позо Рамос

Как использовать тип данных defaultdict для работы с отсутствующими ключами

Чтобы воспользоваться типом данных defaultdict в Python, необходимо импортировать его из модуля collections. Он может принимать один аргумент - функцию, которая будет вызываться при попытке доступа к отсутствующему ключу. Функция должна возвращать значение по умолчанию для отсутствующего ключа.

from collections import defaultdict
# Создание defaultdict с функцией в качестве аргумента
d = defaultdict(int)
# Доступ к несуществующему ключу, будет создан новый ключ с значением по умолчанию (0)
d['a'] += 1
print(d) # defaultdict(<class 'int'>, {'a': 1})

Группировка элементов

Одним из распространенных методов использования defaultdict является группировка элементов по определенному критерию. Рассмотрим следующий пример:

from collections import defaultdict
# Исходный список элементов
data = [('apple', 1), ('banana', 2), ('cherry', 3), ('apple', 4), ('banana', 5)]
# Создание defaultdict для группировки по имени фрукта
grouped_data = defaultdict(list)
# Группировка элементов
for fruit, value in data:
grouped_data[fruit].append(value)
# Вывод результатов
for fruit, values in grouped_data.items():
print(fruit, values)

Результат:

apple [1, 4]
banana [2, 5]
cherry [3]

Группировка уникальных элементов

Используя defaultdict, можно также легко создать словарь, в котором значениями будут являться уникальные элементы из исходного списка:

from collections import defaultdict
# Исходный список элементов
data = ['apple', 'banana', 'cherry', 'apple', 'banana']
# Создание defaultdict для группировки уникальных элементов
grouped_data = defaultdict(set)
# Группировка уникальных элементов
for item in data:
grouped_data[item].add(item)
# Вывод результатов
for item, values in grouped_data.items():
print(item, values)

Результат:

apple {'apple'}
banana {'banana'}
cherry {'cherry'}

Подсчет элементов

С помощью defaultdict можно также легко подсчитать количество вхождений каждого элемента в исходном списке:

from collections import defaultdict
# Исходный список элементов
data = ['apple', 'banana', 'cherry', 'apple', 'banana']
# Создание defaultdict для подсчета элементов
count = defaultdict(int)
# Подсчет элементов
for item in data:
count[item] += 1
# Вывод результатов
for item, count in count.items():
print(item, count)

Результат:

apple 2
banana 2
cherry 1

Накопление значений

defaultdict также может использоваться для накопления значений элементов. Рассмотрим пример накопления суммы чисел по каждому ключу:

from collections import defaultdict
# Исходные данные
data = [('apple', 1), ('banana', 2), ('cherry', 3), ('apple', 4), ('banana', 5)]
# Создание defaultdict для накопления суммы значений
total = defaultdict(int)
# Накопление значений
for fruit, value in data:
total[fruit] += value
# Вывод результатов
for fruit, total_value in total.items():
print(fruit, total_value)

Результат:

apple 5
banana 7
cherry 3

Углубленное изучение defaultdict

defaultdict vs dict

Важно понимать разницу между типами defaultdict и dict. Основное отличие заключается в том, что defaultdict автоматически создает отсутствующий ключ и генерирует для него значение по умолчанию, тогда как для обычного словаря dict при попытке доступа к отсутствующему ключу будет возбуждено исключение KeyError.

Пример:

from collections import defaultdict
d1 = defaultdict(int)
d2 = {}
print(d1['a']) # 0
print(d2['a']) # KeyError: 'a'

defaultdict.default_factory

defaultdict имеет атрибут default_factory, который позволяет установить функцию по умолчанию для создания значений отсутствующих ключей. Если default_factory не указан, то значение по умолчанию будет равно None.

Пример:

from collections import defaultdict
d = defaultdict(list)
print(d.default_factory) # <class 'list'>

defaultdict vs dict.setdefault()

Также стоит отметить разницу между defaultdict и методом setdefault() обычного словаря dict. Оба способа позволяют обработать отсутствующие ключи, но defaultdict обладает преимуществом в том, что он не изменяет сам словарь при попытке доступа к отсутствующему ключу.

Пример:

from collections import defaultdict
d1 = defaultdict(list)
d1['a'].append(1)
print(d1) # defaultdict(<class 'list'>, {'a': [1]})
d2 = {}
d2.setdefault('a', []).append(1)
print(d2) # {'a': [1]}

defaultdict.missing()

defaultdict также предоставляет метод __missing__(), который позволяет определить свое собственное поведение при попытке доступа к отсутствующему ключу. Однако в большинстве случаев использование default_factory является более удобным и предпочтительным.

Эмуляция типа defaultdict вручную

В некоторых ситуациях вам может понадобиться эмулировать работу defaultdict вручную, например, когда вы не можете использовать стандартную библиотеку Python. Для этого вы можете создать свой собственный класс, который будет имитировать поведение defaultdict.

Пример:

class MyDefaultDict(dict):
def __init__(self, default_factory):
super().__init__()
self.default_factory = default_factory
def __missing__(self, key):
value = self.default_factory()
self[key] = value
return value
# Использование MyDefaultDict
d = MyDefaultDict(list)
d['a'].append(1)
print(d) # {'a': [1]}

Передача аргументов в .default_factory

default_factory может принимать аргументы, что позволяет более гибко настраивать создание значений для отсутствующих ключей.

Использование lambda

from collections import defaultdict
# Создание defaultdict с лямбда-функцией в качестве default_factory
d = defaultdict(lambda: 0)
# Доступ к несуществующему ключу, будет создан новый ключ со значением 0
d['a'] += 1
print(d) # defaultdict(<function <lambda> at 0x7f2b65f70700>, {'a': 1})

Использование functools.partial()

from collections import defaultdict
from functools import partial
# Создание defaultdict с partial-функцией в качестве default_factory
d = defaultdict(partial(max, 0))
# Доступ к несуществующему ключу, будет создан новый ключ с максимальным значением 0
d['a'] = 5
print(d['a']) # 5
d['b']
print(d['b']) # 0

Заключение

В этом руководстве вы изучили, как использовать тип данных defaultdict в Python для работы с отсутствующими ключами в словарях. Вы также узнали, когда и почему следует использовать defaultdict вместо обычного словаря dict. Благодаря этому знанию вы сможете эффективно использовать тип данных defaultdict в своих ежедневных задачах программирования на Python.