Как я могу удалить ключ из словаря Python?

При удалении ключа из словаря я использую:

if 'key' in my_dict:
    del my_dict['key']

Есть ли однострочный способ сделать это?


person Tony    schedule 30.06.2012    source источник
comment
Сценарий тестирования для различных методов, предложенных в ответах на этот вопрос: gist.github.com/zigg/6280653 < / а>   -  person zigg    schedule 20.08.2013


Ответы (13)


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

my_dict.pop('key', None)

Это вернет my_dict[key], если key существует в словаре, и None в противном случае. Если второй параметр не указан (т. Е. my_dict.pop('key')) и key не существует, возникает KeyError.

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

del my_dict['key']

Это вызовет KeyError, если ключа нет в словаре.

person Sven Marnach    schedule 30.06.2012
comment
Иногда преимущество использования pop() перед del: он возвращает значение для этого ключа. Таким образом, вы можете получить и удалить запись из dict в одной строке кода. - person kratenko; 18.08.2013
comment
В вопросе сохранять ценность не требуется. Это только добавит ненужной сложности. Ответ от @zigg (ниже) намного лучше. - person Salvatore Cosentino; 14.06.2017
comment
@SalvatoreCosentino Я не могу понять ваш аргумент. Чем код в этом ответе сложнее, чем код в другом ответе? - person Sven Marnach; 15.06.2017
comment
Привет @SvenMarnach, чтобы 1) На мой взгляд, ответ ниже более элегантен (например, обработка исключения) 2) использование pop в большинстве языков программирования (и структур данных) используется, когда вы хотите сохранить удаленное значение, и вопрос только об удалении ключа. Возврат значения, которое никогда не использовалось, было бы просто неэффективным. - person Salvatore Cosentino; 15.06.2017
comment
@SalvatoreCosentino Нет, игнорирование возвращаемого значения функции вовсе не неэффективно. Напротив, это решение намного быстрее, чем решение _1 _ / _ 2_, если ключ не существует. Возможно, вам будет легче читать одно или другое, и это нормально. Оба являются идиоматическим Python, поэтому выбирайте то, что вам больше нравится. Но утверждать, что этот ответ более сложный или неэффективный, просто не имеет смысла. - person Sven Marnach; 15.06.2017
comment
Проблема с этим подходом заключается в том, что он возвращает значение key, а не исходный dict. Итак, {'a':1, 'b':2}.pop('b') возвращает 2 вместо {'a':1} - person user5359531; 01.08.2018
comment
@ user5359531 Я не понимаю. Как это проблема? Ни один из методов встроенных типов Python не возвращает self, поэтому было бы довольно удивительно, если бы это сделал этот. - person Sven Marnach; 02.08.2018
comment
при попытке использовать эту функцию в понимании списка, что является довольно типичным вариантом использования однострочников в Python. Преобразование одного списка диктовок в другой, в котором удалены некоторые ключи. - person user5359531; 03.08.2018
comment
@ user5359531 Обычно следует избегать составления списков с побочными эффектами, поскольку они сбивают с толку. Если dict.pop() вернет исходный dict, то b = [d.pop("key") for d in a] изменит оба списка, a и b, поскольку они оба будут использовать одни и те же объекты словаря. Это одна из причин, по которой в Python существует соглашение о том, что изменяющие методы не имеют возвращаемого значения. (Фактически, dict.pop() является исключением из этого соглашения, но он не нарушает дух соглашения.) - person Sven Marnach; 03.08.2018
comment
@ user5359531 Если вы хотите изменить список словарей на месте, используйте цикл for: for d in a: d.pop("key", None). Если вы хотите сохранить исходные словари без изменений, сначала скопируйте их: b = [d.copy() for d in a]. - person Sven Marnach; 03.08.2018
comment
полезный вариант использования: создание иерархии из простого словаря, как в new_dict = {my_dict.pop('key_to_promote'): my_dict} - person matanster; 23.05.2020
comment
Эквивалентом структуры данных set является операция discard. Например, my_set.discard(k) удалит k без повышения KeyError, тогда как my_set.remove(k) вызовет KeyError, если k отсутствует в наборе. - person Ambareesh; 22.08.2020

В частности, чтобы ответить "есть ли однострочный способ сделать это?"

if 'key' in my_dict: del my_dict['key']

... ну вы спросили ;-)

Однако следует учитывать, что этот способ удаления объекта из dict не атомарен - возможно, что 'key' может находиться в my_dict во время выполнения оператора if, но может быть удален до выполнения del, и в этом случае del завершится ошибкой с KeyError. Учитывая это, безопаснее всего было бы использовать dict.pop или что-то вроде

try:
    del my_dict['key']
except KeyError:
    pass

что, конечно, определенно не однострочное.

person zigg    schedule 30.06.2012
comment
Да, pop определенно более лаконичен, хотя есть одно ключевое преимущество такого подхода: сразу становится понятно, что он делает. - person zigg; 01.07.2012
comment
Выражение try/except дороже. Исключение возникает медленно. - person Chris Barker; 20.08.2013
comment
@ChrisBarker Я обнаружил, что если ключ существует, try немного быстрее, а если нет, try действительно намного медленнее. pop довольно последовательна, но медленнее, чем все, кроме try с отсутствующим ключом. См. gist.github.com/zigg/6280653. В конечном счете, это зависит от того, как часто вы ожидаете, что ключ действительно будет в словаре, и от того, нужна ли вам атомарность - и, конечно же, от того, участвуете ли вы в преждевременной оптимизации;) - person zigg; 20.08.2013
comment
Я считаю, что нельзя упускать из виду ценность ясности. +1 за это. - person Juan Carlos Coto; 01.07.2014
comment
что касается расходов на попытку / за исключением, вы также можете пойти if 'key' in mydict: #then del.... Мне нужно было вытащить ключ / val из dict для правильного анализа, pop не было идеальным решением. - person Marc; 09.07.2015
comment
@datamafia Однако, как и все if k in d решения, это не атомарно, и del может дать сбой. Почему pop у вас не сработало? - person zigg; 14.07.2015
comment
@zigg У меня была шаткая структура данных, короче говоря, мне нужно было заказать dict через пару ключ / val, вложенную в dict. Поэтому я использовал if key in, чтобы определить, находится ли ключ устранения проблемы в dict, скопировать во временный dict, выполнить упорядочение lambda / list comp ordering dict, а затем добавить значение обратно. Pop и del работают одинаково в этом экземпляре. Условный квалификатор позволял поместить ключ / val в temp dict для выполнения работы. Это была работа для некоторого коричневого кода, не идеальная, но мы двинулись дальше. pop() тоже сработало бы, мне нравится многословие дель. Попробовать / поймать может быть дорого. - person Marc; 14.07.2015
comment
Попробуйте поймать - правильный способ сделать это. это не неловко. - person PythonTester; 11.03.2016
comment
@Marc, если вам нужно обработать пару ключ: значение, используйте вместо этого popitem(). Поместите его в цикл while, чтобы использовать весь dict. - person Gloweye; 29.08.2018
comment
@ChrisBarker Python - это язык, предназначенный для управления исключениями, они лишь незначительно медленнее, чем другие варианты, см. stackoverflow.com/questions/2522005/ - person juan Isaza; 05.03.2021

Мне потребовалось некоторое время, чтобы понять, что именно делает my_dict.pop("key", None). Поэтому я добавлю это как ответ, чтобы сэкономить время на поиске в Google:

pop(key[, default])

Если ключ находится в словаре, удалите его и верните его значение, иначе верните default. Если default не указан и ключ отсутствует в словаре, возникает KeyError.

Документация

person Akavall    schedule 04.03.2013
comment
Просто введите help (dict.pop) в интерпретаторе Python. - person David Mulder; 06.08.2013
comment
help () и dir () могут быть вашими друзьями, когда вам нужно знать, что что-то делает. - person David Mulder; 06.08.2013
comment
или dict.pop? в IPython. - person Erik Kaplun; 13.04.2014

del my_dict[key] немного быстрее, чем my_dict.pop(key), для удаления ключа из словаря, когда ключ существует

>>> import timeit
>>> setup = "d = {i: i for i in range(100000)}"

>>> timeit.timeit("del d[3]", setup=setup, number=1)
1.79e-06
>>> timeit.timeit("d.pop(3)", setup=setup, number=1)
2.09e-06
>>> timeit.timeit("d2 = {key: val for key, val in d.items() if key != 3}", setup=setup, number=1)
0.00786

Но когда ключ не существует, if key in my_dict: del my_dict[key] немного быстрее, чем my_dict.pop(key, None). Оба они как минимум в три раза быстрее, чем del в операторе _7 _ / _ 8_:

>>> timeit.timeit("if 'missing key' in d: del d['missing key']", setup=setup)
0.0229
>>> timeit.timeit("d.pop('missing key', None)", setup=setup)
0.0426
>>> try_except = """
... try:
...     del d['missing key']
... except KeyError:
...     pass
... """
>>> timeit.timeit(try_except, setup=setup)
0.133
person Peter Smit    schedule 07.12.2016
comment
@Boris - это полезно в качестве общего упражнения. - person K--; 07.04.2020
comment
@daisy, я говорю, что вы должны выбрать наиболее читаемый синтаксис, а не операцию, которая на 300 наносекунд быстрее (это буквально разница между del и pop из первого набора таймингов выше) - person Boris; 07.04.2020
comment
Кроме того, эти операции выполняются настолько быстро, что эти тайминги ненадежны. - person Boris; 07.04.2020

Если вам нужно удалить много ключей из словаря в одной строке кода, я думаю, что использование map () довольно лаконично и читаемо на Pythonic:

myDict = {'a':1,'b':2,'c':3,'d':4}
map(myDict.pop, ['a','c']) # The list of keys to remove
>>> myDict
{'b': 2, 'd': 4}

И если вам нужно отловить ошибки, когда вы вставляете значение, которого нет в словаре, используйте лямбда внутри map () следующим образом:

map(lambda x: myDict.pop(x,None), ['a', 'c', 'e'])
[1, 3, None] # pop returns
>>> myDict
{'b': 2, 'd': 4}

или в python3 вместо этого вы должны использовать понимание списка:

[myDict.pop(x, None) for x in ['a', 'c', 'e']]

Оно работает. И «e» не вызывало ошибки, даже если myDict не имел ключа «e».

person Marc Maxmeister    schedule 16.09.2015
comment
Это не будет работать в Python 3, потому что map и друзья теперь ленивы и возвращают итераторы. Использование map для устранения побочных эффектов обычно считается плохой практикой; стандартный for ... in цикл был бы лучше. См. Представления и итераторы вместо списков для получения дополнительной информации. - person Greg Krimer; 07.11.2015
comment
Независимо от вкуса и стиля практики, списки должны работать в Py3 [myDict.pop(i, None) for i in ['a', 'c']], поскольку они предлагают общую альтернативу mapfilter). - person Michael Ekoka; 22.10.2017
comment
@MichaelEkoka, вы не должны использовать составление списков из-за их побочных эффектов, используйте обычный цикл for ... in. - person Boris; 03.04.2020
comment
@Boris Вы, наверное, правы. Мой ответ конкретно относится к использованию map(), которое часто используется из-за его побочных эффектов. Рекомендуемая альтернатива в Python - это понимание списка, которое, на мой взгляд, все еще достаточно читабельно и когнитивно легкое как однострочное (см. Вопрос). Обе конструкции, используемые только из-за своих побочных эффектов, действительно приводят к бесполезному списку, который может быть неэффективным. Что касается Python3, я не знаю встроенной функции, которая может безопасно и элегантно выполнять итерацию через выражение генератора без дорогостоящих побочных продуктов, например. loop(d.pop(k) for k in ['a', 'b']). - person Michael Ekoka; 07.04.2020
comment
Меня забавляет, что в мой самый популярный ответ за все время включены некоторые хаки, которые я бы никогда не использовал. Понимание списка (вариант 3), на мой взгляд, является наименее плохим подходом. Используйте это. - person Marc Maxmeister; 08.04.2020
comment
@MichaelEkoka встроенная функция - это цикл for: for k in ['a', 'b']: d.pop(k). Зачем нужен другой способ? Если вам нужно, чтобы он занимал только одну строку, вы можете поместить вторую часть цикла for в ту же строку. - person Boris; 04.05.2020
comment
@Boris Как я уже сказал, мой ответ относится конкретно к использованию map()filter()), что означает, что если вам нужно использовать любой из этих двух, вы можете просто использовать понимание списка. Я также признаю, что и понимание списка, и map() расточительны, поскольку создают ненужный список в качестве побочного продукта. Остается, что их более функциональный синтаксис по-прежнему ценится и желателен многими программистами (например, stackoverflow.com/q/1080026/56974 ). Это вопрос стиля. К сожалению, Python не предлагает встроенного функционального способа зацикливания и выполнения без побочных продуктов. - person Michael Ekoka; 04.05.2020

Вы можете использовать понимание словаря, чтобы создать новый словарь с удаленным ключом:

>>> my_dict = {k: v for k, v in my_dict.items() if k != 'key'}

Вы можете удалить по условиям. Нет ошибки, если key не существует.

person Shameem    schedule 07.12.2016
comment
Этот ответ отличается от других, потому что у него нет побочных эффектов (он не изменяет исходный словарь). - person Jeff D. White; 06.08.2020
comment
Хотя, вероятно, я бы сделал это так же, но это создает в памяти совершенно новый словарь, копируя (ссылки на) объекты в новый словарь. Затем он сохраняет его под старым именем. Для больших словарей это может занять некоторое время. del dict[key] или dict.pop(key) будет быстрее во всех случаях. - person mazunki; 20.11.2020

Используя ключевое слово "del":

del dict[key]
person Sarthak Gupta    schedule 02.05.2018

Вы можете использовать обработку исключений, если хотите быть очень подробным:

try: 
    del dict[key]

except KeyError: pass

Однако это медленнее, чем метод pop(), если ключ не существует.

my_dict.pop('key', None)

Для нескольких ключей это не имеет значения, но если вы делаете это неоднократно, лучше подойдет второй метод.

Самый быстрый подход такой:

if 'key' in dict: 
    del myDict['key']

Но этот метод опасен, потому что, если 'key' будет удален между двумя строками, будет поднят KeyError.

person Alec    schedule 25.05.2019

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

Использование ключевого слова del; это почти такой же подход, как и у вас -

 myDict = {'one': 100, 'two': 200, 'three': 300 }
 print(myDict)  # {'one': 100, 'two': 200, 'three': 300}
 if myDict.get('one') : del myDict['one']
 print(myDict)  # {'two': 200, 'three': 300}

Или

Мы можем сделать следующее:

Но следует иметь в виду, что в этом процессе он фактически не удаляет какой-либо ключ из словаря, а не делает определенный ключ исключенным из этого словаря. Вдобавок я заметил, что он вернул словарь, который не был упорядочен так же, как myDict.

myDict = {'one': 100, 'two': 200, 'three': 300, 'four': 400, 'five': 500}
{key:value for key, value in myDict.items() if key != 'one'}

Если мы запустим его в оболочке, он выполнит что-то вроде {'five': 500, 'four': 400, 'three': 300, 'two': 200} - обратите внимание, что он не такой же, как myDict. Опять же, если мы попытаемся вывести myDict, мы сможем увидеть все ключи, включая те, которые мы исключили из словаря с помощью этого подхода. Однако мы можем создать новый словарь, присвоив переменной следующий оператор:

var = {key:value for key, value in myDict.items() if key != 'one'}

Теперь, если мы попытаемся распечатать его, он будет следовать родительскому порядку:

print(var) # {'two': 200, 'three': 300, 'four': 400, 'five': 500}

Или

Используя метод pop().

myDict = {'one': 100, 'two': 200, 'three': 300}
print(myDict)

if myDict.get('one') : myDict.pop('one')
print(myDict)  # {'two': 200, 'three': 300}

Разница между del и pop заключается в том, что, используя метод pop(), мы действительно можем сохранить значение ключа, если это необходимо, как показано ниже:

myDict = {'one': 100, 'two': 200, 'three': 300}
if myDict.get('one') : var = myDict.pop('one')
print(myDict) # {'two': 200, 'three': 300}
print(var)    # 100

Если вы сочтете это полезным, укажите эту суть для дальнейшего использования.

person M.Innat    schedule 19.05.2018
comment
Не используйте if myDict.get('one') для проверки наличия ключа! Это не удается, если myDict ['one'] имеет ложное значение. Кроме того, dicts не имеют внутреннего порядка, поэтому упоминать его не имеет смысла. - person Rob; 28.02.2019
comment
@Rob dicts упорядочены по порядку вставки, начиная с CPython 3.6 и всех других реализаций Python, начиная с 3.7. - person Boris; 03.04.2020

Тип данных Словарь имеет метод dict_name.pop(item), который можно использовать для удаления пары ключ: значение из словаря.

a={9:4,2:3,4:2,1:3}
a.pop(9)
print(a)

Это даст результат как:

{2: 3, 4: 2, 1: 3}

Таким образом, вы можете удалить элемент из словаря одной строкой.

person Anshika Singh    schedule 21.06.2020

Другой способ - использовать items () + dict computing.

items () в сочетании с пониманием dict также может помочь нам в решении задачи удаления пары ключ-значение, но у него есть недостаток, заключающийся в том, что он не является техникой dict на месте. Фактически, новый dict, если он создан, за исключением ключа, который мы не хотим включать.

test_dict = {"sai" : 22, "kiran" : 21, "vinod" : 21, "sangam" : 21}

# Printing dictionary before removal
print ("dictionary before performing remove is : " + str(test_dict))

# Using items() + dict comprehension to remove a dict. pair
# removes  vinod
new_dict = {key:val for key, val in test_dict.items() if key != 'vinod'}

# Printing dictionary after removal
print ("dictionary after remove is : " + str(new_dict))

Выход:

dictionary before performing remove is : {'sai': 22, 'kiran': 21, 'vinod': 21, 'sangam': 21}
dictionary after remove is : {'sai': 22, 'kiran': 21, 'sangam': 21}
person Sai Kiran Sangam    schedule 17.09.2019
comment
на самом деле это не делает того, о чем просят - он создает новый dict с удаленными ненужными ключами. Кроме того, перебор всех ключей для удаления одного выполняется за O (1) за время O (N). - person anon01; 05.05.2021

Я предпочитаю неизменную версию

foo = {
    1:1,
    2:2,
    3:3
}
removeKeys = [1,2]
def woKeys(dct, keyIter):
    return {
        k:v
        for k,v in dct.items() if k not in keyIter
    }

>>> print(woKeys(foo, removeKeys))
{3: 3}
>>> print(foo)
{1: 1, 2: 2, 3: 3}
person CervEd    schedule 14.06.2019

Единый фильтр по ключу

  • вернуть «ключ» и удалить его из my_dict, если «ключ» существует в my_dict
  • return None, если "ключ" не существует в my_dict

это изменит my_dict на месте (изменяемый)

my_dict.pop('key', None)

Множественные фильтры по клавишам

создать новый dict (неизменяемый)

dic1 = {
    "x":1,
    "y": 2,
    "z": 3
}

def func1(item):
    return  item[0]!= "x" and item[0] != "y"

print(
    dict(
        filter(
            lambda item: item[0] != "x" and item[0] != "y", 
            dic1.items()
            )
    )
)
person ZenG    schedule 25.04.2020