tgoop.com/pro_python_code/1809
Create:
Last Update:
Last Update:
🐍 Задача с подвохом для продвинутых Python-разработчиков
🔹 Уровень: Advanced
🔹 Темы: особенности defaultdict
, побочные эффекты, mutability, ловушки с list
и dict
📌 Условие
Рассмотрим следующий код:
from collections import defaultdict
def make_dict():
return {"count": 0}
d = defaultdict(make_dict)
d["a"]["count"] += 1
d["b"]["count"] += 1
d["a"]["count"] += 1
print(d)
❓ Вопросы
1. Что будет выведено на экран?
2. Почему результат может оказаться неожиданным при использовании других вариантов реализации?
3. Что изменится, если использовать
make_dict()
без функции-обёртки?🔍 Разбор
✅ Ожидаемый вывод:
defaultdict(<function make_dict at 0x...>, {'a': {'count': 2}, 'b': {'count': 1}})
🔧 Почему так происходит
-
defaultdict
вызывает make_dict()
каждый раз, когда ключа нет в словаре.- Для каждого нового ключа (`"a"` и
"b"`) создаётся **новый** словарь `{"count": 0}
.-
d["a"]["count"] += 1
увеличивает значение "count"
у собственного словаря a
.⚠️ Подвох
Если бы вместо
make_dict
использовали один и тот же объект (например, через `lambda: some_dict`), то все ключи ссылались бы на один и тот же словарь — и значения начали бы "перетекать" между ключами:
shared = {"count": 0}
d = defaultdict(lambda: shared)
Тогда итог мог бы быть таким:
{'a': {'count': 2}, 'b': {'count': 2}} # неожиданно!
🧠 Вывод
- Никогда не используйте изменяемый объект напрямую как значение по умолчанию в
defaultdict
. - Используй функции-фабрики, чтобы избежать общих ссылок между элементами.
- Проверяй поведение при работе со сложными структурами (`list`, `dict`) в качестве значений по умолчанию.
# Правильно:
defaultdict(lambda: {"count": 0})
# Ошибочно:
defaultdict(lambda: some_shared_dict)
📌 Используй
copy.deepcopy()
или фабричные функции, если создаёшь вложенные структуры.BY Python RU
Share with your friend now:
tgoop.com/pro_python_code/1809