Collections.defaultdict: примеры (PYTHON)

Использование defaultdict из модуля collections в Python
Раздел: Коллекции, Словари
collections.defaultdict(default_factory: callable or None = None): defaultdict

Общее описание defaultdict

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

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

Аргумент default_factory принимает вызываемый объект без параметров, который возвращает значение по умолчанию. При передаче None поведение совпадает с обычным словарем, вызывая исключение KeyError при обращении к отсутствующему ключу.

Возвращается экземпляр подкласса dict, который переопределяет метод __missing__() для создания значений через указанную фабрику.

Основные примеры применения

Подсчет элементов с использованием int:

from collections import defaultdict
word_count = defaultdict(int)
for word in ['apple', 'banana', 'apple', 'cherry']:
    word_count[word] += 1
print(word_count)
defaultdict(, {'apple': 2, 'banana': 1, 'cherry': 1})

Группировка по категориям с list:

from collections import defaultdict
data = [('fruit', 'apple'), ('vegetable', 'carrot'), ('fruit', 'banana')]
grouped = defaultdict(list)
for category, item in data:
    grouped[category].append(item)
print(grouped)
defaultdict(, {'fruit': ['apple', 'banana'], 'vegetable': ['carrot']})

Создание множеств с set:

from collections import defaultdict
unique_data = defaultdict(set)
unique_data['colors'].add('red')
unique_data['colors'].add('blue')
unique_data['shapes'].add('circle')
print(unique_data)
defaultdict(, {'colors': {'red', 'blue'}, 'shapes': {'circle'}})

Использование lambda для сложных значений:

from collections import defaultdict
default_with_lambda = defaultdict(lambda: {'count': 0, 'total': 0.0})
default_with_lambda['a']['count'] += 1
print(default_with_lambda['b'])
{'count': 0, 'total': 0.0}

Аналоги в Python

dict.setdefault(key, default): метод устанавливает значение по умолчанию для ключа только при его отсутствии, возвращая текущее значение. Может быть менее эффективным при частом вызове.

collections.Counter: специализированный словарь для подсчета хешируемых объектов, предоставляет дополнительные методы для работы со счетчиками.

Проверка через get(): обычный словарь позволяет использовать метод get() с значением по умолчанию, но без автоматического добавления ключа.

Выбор зависит от контекста: defaultdict удобен для накопления данных в циклах, Counter для простого подсчета, а setdefault для единичных операций.

Распространенные ошибки

Передача невызываемого объекта в default_factory:

from collections import defaultdict
try:
    d = defaultdict(123)
except Exception as e:
    print(f'Ошибка: {type(e).__name__}: {e}')
Ошибка: TypeError: first argument must be callable or None

Неожиданное разделение ссылок при использовании изменяемых объектов:

from collections import defaultdict
default_list = defaultdict(list)
default_list['a'].append(1)
print(default_list['b'])  # Новый список, а не [1]
[]

Использование default_factory, которая требует аргументов:

from collections import defaultdict
try:
    d = defaultdict(lambda x: x*2)
    print(d[5])
except Exception as e:
    print(f'Ошибка: {type(e).__name__}')
Ошибка: TypeError

Изменения в версиях Python

В Python 3.9 добавлена поддержка операторов объединения | и |= для defaultdict. Начиная с Python 3.10, улучшена читаемость строкового представления объектов defaultdict. Существенных изменений в API функции не происходило.

Расширенные примеры использования

Вложенный defaultdict для создания многомерных структур:

Пример python
from collections import defaultdict
deep_default = defaultdict(lambda: defaultdict(dict))
deep_default['level1']['level2']['key'] = 'value'
print(deep_default['level1']['level2'])
{'key': 'value'}

Использование класса в качестве фабрики:

Пример python
from collections import defaultdict
class Config:
    def __init__(self):
        self.value = None
    def __repr__(self):
        return f'Config(value={self.value})'
configs = defaultdict(Config)
configs['server'].value = 'localhost'
print(configs['server'])
print(configs['client'])
Config(value=localhost)
Config(value=None)

Группировка с условием:

Пример python
from collections import defaultdict
numbers = [1, 2, 3, 4, 5, 6]
grouped = defaultdict(list)
for num in numbers:
    key = 'even' if num % 2 == 0 else 'odd'
    grouped[key].append(num)
print(grouped)
defaultdict(, {'odd': [1, 3, 5], 'even': [2, 4, 6]})

Эмуляция графа через список смежности:

Пример python
from collections import defaultdict
graph = defaultdict(set)
graph['A'].add('B')
graph['A'].add('C')
graph['B'].add('A')
print(graph)
defaultdict(, {'A': {'B', 'C'}, 'B': {'A'}})

Кэширование с ограничением по времени через defaultdict и datetime:

Пример python
from collections import defaultdict
from datetime import datetime, timedelta
cache = defaultdict(lambda: {'time': None, 'data': None})
def get_cached(key):
    entry = cache[key]
    if entry['time'] and datetime.now() - entry['time'] < timedelta(minutes=5):
        return entry['data']
    return None
cache['test']['time'] = datetime.now()
cache['test']['data'] = 'cached_value'
print(get_cached('test'))
cached_value

Реализации в других языках

JavaScript: объекты или Map с ручной проверкой.

let map = new Map();
map.set('a', (map.get('a') || 0) + 1);
console.log(map.get('a'));
1

Java: HashMap с методами getOrDefault и computeIfAbsent.

Map map = new HashMap<>();
map.put("count", map.getOrDefault("count", 0) + 1);
System.out.println(map.get("count"));
1

PHP: ассоциативные массивы с null-коалесцирующим оператором.

$arr = [];
$arr['key'] = ($arr['key'] ?? 0) + 1;
echo $arr['key'];
1

C#: Dictionary с проверкой через TryGetValue.

var dict = new Dictionary();
dict["key"] = dict.ContainsKey("key") ? dict["key"] + 1 : 1;
Console.WriteLine(dict["key"]);
1

Go: карты с явной проверкой второго возвращаемого значения.

m := make(map[string]int)
if v, ok := m["key"]; ok {
    m["key"] = v + 1
} else {
    m["key"] = 1
}
fmt.Println(m["key"])
1

Kotlin: getOrPut для изменяемых коллекций.

val map = mutableMapOf()
map["key"] = map.getOrPut("key") { 0 } + 1
println(map["key"])
1

Lua: таблицы с метатаблицами через __index.

local mt = { __index = function(t, k) return 0 end }
local t = setmetatable({}, mt)
t["x"] = t["x"] + 5
print(t["x"])
5

SQL: COALESCE в запросах SELECT. В отличие от Python, defaultdict интегрирован в структуру данных и автоматизирует процесс.

питон collections.defaultdict function comments

En
Collections.defaultdict dict subclass that calls a factory function to supply missing values