Удаление: del, pop и popitem
Четыре способа убрать данные из словаря: del молча удаляет пару, pop отдаёт значение, popitem снимает последнюю пару, clear чистит всё. Плюс разбор, почему удалять во время обхода нельзя.
Редакция Питоники
В прошлом уроке пары появлялись и обновлялись присваиванием. Осталась зеркальная задача — убрать лишнее: товар снят с продажи, запись удалена, счётчик сброшен. У словаря четыре инструмента на все случаи: del, pop, popitem и clear. Отличаются они тем, возвращают ли значение и что делают с отсутствующим ключом: del удаляет пару молча, pop сначала отдаёт значение, и только потом забывает ключ.
del: удалить пару
stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}
del stock['хлеб']
print(stock)
{'молоко': 12, 'сыр': 8}Оператор del убирает пару целиком — и ключ, и значение, — и ничего не возвращает. Ключа 'хлеб' больше нет: обращение к нему теперь упало бы с KeyError из урока про строгий доступ. И у самого del тот же нрав: удалить отсутствующий ключ нельзя — словарь не догадывается, хотели вы что-то убрать или просто ошиблись.
pop: удалить и забрать значение
stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}
price = stock.pop('сыр')
print(price)
print(stock)
8
{'молоко': 12, 'хлеб': 5}Метод pop — это «достать и выбросить» одним движением: он вернул значение 8 и тут же удалил пару. Отсутствующий ключ pop тоже не прощает — но у него есть запасной путь, которого нет у del: второй аргумент. Он вернётся вместо ошибки, если ключа нет:
stock = {'молоко': 12}
print(stock.pop('кефир', 0))
print(stock.pop('кефир', 'нет такого'))
print(stock)
0
нет такого
{'молоко': 12}popitem и clear: снять последнюю пару и опустошить всё
stock = {'молоко': 12, 'хлеб': 5}
last = stock.popitem()
print(last)
print(stock)
stock.clear()
print(stock)
('хлеб', 5)
{'молоко': 12}
{}Метод popitem вызывается без аргументов: он снимает последнюю добавленную пару и отдаёт её кортежем из двух элементов — ключа и значения. Метод clear удаляет все пары разом, оставляя пустой словарь. popitem удобен, когда словарь обрабатывают как стопку: снял верхнюю пару — поработал с ней. clear — приём резковатый: он опустошает всё без разбора, поэтому чаще пары удаляют по одной — через del или pop, а проверку «а есть ли ключ вообще» делают оператором in из следующего урока.
popitem как стопка: снимаем всё по порядку
Раз popitem забирает последнюю добавленную пару, словарь превращается в стопку: работа идёт с конца. Это редко, но иногда нужно именно такое поведение — например, обработать задания в порядке поступствия и разбирать их с конца. Цикл с popitem выглядит так.
data = {'a': 1, 'b': 2, 'c': 3}
while True:
try:
key, value = data.popitem()
except KeyError:
break
print(key, value)
c 3 b 2 a 1
Пара-кортеж распаковывается прямо в две переменные — key, value = data.popitem(). Цикл заканчивается, когда словарь опустеет и popitem начнёт бросать KeyError: его ловим и выходим из цикла через break. Важно: в блоке except ничего не печатается: пустой словарь — это штатное завершение, а не ошибка.
Удаление во время обхода: почему нельзя
Отдельная грабли, на которую наступает почти каждый, кто впервые чистит словарь. Логика программиста простая: «просматриваю позиции, не годятся — удаляю». Python так не работает: он запрещает менять размер словаря посреди обхода и обрывает программу с RuntimeError. Причина техническая — обход держит в памяти указатель на текущую позицию таблицы, и удаление пары сдвигает всё следом, указатель уезжает мимо, и обход начинает повторять элементы или пропускать их.
stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}
removed = []
for name in list(stock):
if stock[name] < 6:
removed.append(name)
del stock[name]
print('удалено:', removed)
print(stock)
удалено: ['хлеб']
{'молоко': 12, 'сыр': 8}Обёртка list(stock) — обязательная деталь приёма: цикл идёт по копии ключей, и удаление из оригинала во время обхода уже безопасно. Собранные имена кладём в отдельный список removed — заодно получится готовый отчёт о том, что именно вычистили. Второй вариант — собрать новый словарь из нужных пар и просто заменить старый; оба подхода одинаково рабочие, первый чуть экономнее по памяти.
stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}
try:
for name in stock:
if stock[name] < 6:
del stock[name]
except RuntimeError as e:
print('RuntimeError:', e)
RuntimeError: dictionary changed size during iteration
Вот как это выглядит «в лоб». Текст ошибки достаточно красноречив: dictionary changed size during iteration — размер словаря изменился во время итерации. Никакой номера строки и никакого имени ключа здесь нет, потому что это не ошибка данных, а ошибка самого способа обхода. Лечится только переносом удалений за пределы цикла.
del или pop: как выбрать
Возвращаясь к выбору инструмента. Правило простое: если удалённое значение больше не нужно — del, он короче и молчит; если значение надо куда-то записать перед удалением — pop, он возвращает его. Разница в одну строку, но на практике pop спасает от ситуации, когда значение забыли сохранить и потом пришлось искать его в другом месте.
stock = {'молоко': 12, 'хлеб': 5}
print(stock.pop('молоко'))
print(stock)
print(stock.pop('молоко', 'нет'))
12
{'хлеб': 5}
нетТретий вызов — уже другой случай: ключа 'молоко' в словаре нет, и вместо KeyError вернулось умолчание 'нет'. Строка вместо числа выбрана специально, чтобы её было видно в выводе. В реальном коде подставляют то, что соответствует типу: ноль для чисел, пустую строку для текста.
Второй способ почистить: собрать новый словарь
Про list(stock) мы сказали, что есть и другой путь: не трогать старый словарь, а собрать новый из нужных пар и подставить его на место старого. Выглядит это как генератор словаря — и короче, и понятнее, чем цикл с удалением.
stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}
fresh = {name: amount for name, amount in stock.items() if amount >= 6}
print(fresh)
print(stock)
{'молоко': 12, 'сыр': 8}
{'молоко': 12, 'хлеб': 5, 'сыр': 8}Старый словарь при этом остаётся нетронутым — а это важно, если на него ссылаются другие куски кода. Приём называют «новый словарь вместо старого», и в рабочих проектах мы применяем его чаще, чем удаление: сбой на промежуточном шаге не оставит данные в неконсистентном состоянии.
Иногда удалять не нужно вовсе. В одном сервисе заказ нельзя было убрать из словаря: его статус смотрели три разных обработчика, и если бы пара исчезла, обработчик решил бы, что заказа не существует, и списал его повторно. Там оставили в словаре флаг deleted и пропускали такие записи при обходе.
Что дальше
Удалять пары вы теперь умеете четырьмя способами и знаете, почему нельзя удалять прямо в цикле. Дальше — проверка наличия ключа: оператор in отвечает на вопрос «есть ли такой ключ» и никогда не падает. В уроке 7 разбираем его, сравниваем с get и объясняем, почему поиск по ключу быстрый даже на огромных словарях.
Сначала предскажи ответ в голове — это главный навык программиста.
stock = {'чай': 3, 'кофе': 1}
price = stock.pop('чай')
print(price)
print(stock)
d = {'a': 1}
print(d.pop('b', 100))
print(d)
d = {'x': 1, 'y': 2}
del d['x']
print(d)
d.clear()
print(d)
1. Что делает del stock['хлеб']?
2. Чем pop отличается от del?
3. Что вернёт stock.pop('кефир', 0), если ключа 'кефир' в словаре нет?
4. Что вернёт popitem() для словаря {'молоко': 12, 'хлеб': 5}?
5. Что останется в словаре после stock.clear()?
6. Что произойдёт, если удалять пары прямо во время цикла for по словарю?
7. Как удалить пары, не ломая обход?
8. Что вернёт popitem() на пустом словаре?
Дан словарь stock = {'молоко': 12, 'хлеб': 5, 'сыр': 8}. Удали хлеб через del, затем достань и удали сыр одним методом, сохранив цену в переменную. Выведи цену сыра и оставшийся словарь.
Как удалить элемент из словаря в Python?
По ключу — оператором del: del stock['хлеб'] убирает пару целиком. Если удалённое значение ещё нужно, берите метод pop: price = stock.pop('сыр') вернёт значение и удалит пару. Очистить весь словарь разом можно методом clear.
Урок 5: добавление и изменение парЧто лучше: del или pop?
Зависит от того, нужны ли данные. Если значение больше не понадобится — del короче и честнее: пара исчезает молча. Если значение надо куда-то записать перед удалением — pop делает это одним движением и, в отличие от del, умеет не падать на отсутствующем ключе благодаря второму аргументу.
Что будет, если удалить несуществующий ключ?
del и pop без умолчания уронят программу с KeyError — словарь не отличает «нечего удалять» от опечатки. Если ключ может отсутствовать, используйте pop с запасным значением: stock.pop('кефир', 0) — или сначала проверьте наличие ключа оператором in.
Какая пара удаляется методом popitem?
Последняя добавленная: словарь помнит порядок вставки, и popitem снимает пары как стопку — сверху вниз. Пару он отдаёт кортежем из двух элементов: сначала ключ, потом значение. Вызов popitem на пустом словаре — KeyError.
Почему нельзя удалять пары во время перебора словаря?
Обход держит указатель на текущую позицию внутренней таблицы, а удаление пары сдвигает всё следом, и указатель уезжает мимо. Python запрещает такое и обрывает программу с RuntimeError: dictionary changed size during iteration. Спасает приём с list(prices.keys()): цикл идёт по копии ключей, удаление из оригинала во время обхода становится безопасным.
Урок 8: перебор словаряКогда лучше pop, а когда del?
del — когда удалённое значение больше не нужно: короче и ничего не возвращает. pop — когда значение надо сохранить в переменную перед удалением: stock.pop('сыр') вернёт его и уберёт пару. Если ключ может отсутствовать, у pop есть козырь: второй аргумент-умолчание, которого нет у del.
Чем clear отличается от удаления по одной паре?
clear опустошает словарь целиком и не возвращает ничего — все пары исчезают разом. Точечное удаление через del или pop выборочное и часто сопровождается отчётом о том, что именно убрали. clear удобен, когда старые данные больше не нужны, а сам объект словаря ещё понадобится.
Понравился урок? Сошлитесь на него
«del удаляет пару молча, pop сначала отдаёт значение, и только потом забывает ключ.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Словари · Урок 5
Добавление и изменение пар в словаре
Одна операция на всё: d[ключ] = значение добавляет новую пару или заменяет старую. Плюс уникальность ключей, порядок вставки и счётчики, которые пишутся в одну строку.
Словари · Урок 3
Доступ по ключу и KeyError
Что происходит при доступе по несуществующему ключу: настоящий traceback, построчный разбор KeyError, отлов через try/except и случаи, когда падение — правильное поведение.
Словари · Урок 7
in: проверка ключа в словаре
Оператор in отвечает на вопрос «есть ли такой ключ»: проверка перед доступом вместо KeyError, not in, грабли с проверкой значений и причина скорости поиска.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Исключения · Урок 11
KeyError в Python: ошибки словарей
Словарь не нашёл ключ — и честно сказал об этим KeyError. Разбираем объект ошибки, читаем из него ключ и выбираем между get, in и честным исключением.
keyerror словарь pythonpython словарь нет ключа
Множества · Урок 17
Множества и словари Python: hash и общие механизмы
Множество и словарь построены на одном механизме: hash назначает каждому элементу полку, и проверка in становится мгновенной. Ключи словаря — готовое множество, над которым работают & и |.
ключи словаря как множество pythonpython dict keys intersection
Словари · Урок 4
get: безопасное чтение из словаря
Метод get читает словарь без KeyError: без ключа вернёт None, со вторым аргументом — запасное значение. Сравниваем с квадратными скобками, разбираем арифметику с None и молчание get.
python dict getget словарь питон