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


1770

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

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

Есть ли один способ сделать это?


24
Сценарий тестирования для различных методов, предложенных в ответах на этот вопрос: gist.github.com/zigg/6280653
— zigg

Ответы:


2845

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

my_dict.pop('key', None)

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

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

del my_dict['key']

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


153
Иногда преимущество использования pop()over del: он возвращает значение для этого ключа. Таким образом, вы можете получить и удалить запись из dict в одной строке кода.
— Кратенко

7
В вопросе не требуется сохранять значение. Это только добавит ненужную сложность. Ответ от @zigg (ниже) намного лучше.
— Сальваторе

10
@SalvatoreCosentino Я не могу следовать твоим аргументам. Как код в этом ответе является более сложным, чем код в другом ответе?
— Свен Марнач

33
@SalvatoreCosentino Нет, игнорирование возвращаемого значения функции вовсе не является неэффективным. Скорее наоборот - это решение намного быстрее, чем try/ exceptрешение, если ключ не существует. Возможно, вам будет легче читать одну или другую, и это нормально. Оба идиоматических Python, так что выбирайте все, что вы предпочитаете. Но утверждать, что этот ответ является более сложным или неэффективным, просто не имеет смысла.
— Свен Марнах

5
@ user5359531 Я не понимаю. Как это проблема? Ни один из методов встроенных типов Python не вернется self, поэтому было бы довольно удивительно, если бы это сделал.
— Свен Марнах

353

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

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

... хорошо, вы спросили ;-)

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

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

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


27
Да, popэто определенно более лаконично, хотя есть одно ключевое преимущество в этом: сразу понятно, что он делает.
— zigg

4
try/exceptУтверждение является более дорогим. Вызывать исключение медленно.
— Крис Баркер

16
@ChrisBarker Я обнаружил, что если ключ существует, то tryон немного быстрее, хотя, если нет, tryдействительно намного медленнее. popявляется достаточно последовательным, но медленнее, чем все, но tryс отсутствующим ключом. См. Gist.github.com/zigg/6280653 . В конечном счете, это зависит от того, как часто вы ожидаете, что ключ действительно будет в словаре, и от того, нужна ли вам атомарность, и, конечно же, от того, занимаетесь ли вы преждевременной оптимизацией;)
— zigg

9
Я считаю, что значение ясности не следует упускать из виду. +1 за это.
— Хуан Карлос Кото

2
Что касается расходов попробовать / кроме, вы также можете пойти if 'key' in mydict: #then del.... Мне нужно было извлечь ключ / val из dict для правильного разбора, pop не был идеальным решением.
— Марк

153

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

pop(key[, default])

Если ключ находится в словаре, удалите его и верните его значение, иначе верните значение по умолчанию . Если значение по умолчанию не задано, а ключ отсутствует в словаре, a KeyErrorповышается.

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


15
Просто введите help (dict.pop) в интерпретаторе python.
— Дэвид Малдер

13
help () и dir () могут быть вашими друзьями, когда вам нужно знать, что что-то делает.
— Дэвид Малдер

3
или dict.pop?в IPython.
— Эрик Каплун

51

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в try/ exceptоператор:

>>> 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

1
Измерять время такой быстрой операции довольно глупо. Ваш код, вероятно, не станет намного быстрее, потому что вы изменили popна a del. Создание словаря полностью превзойдёт его удаление.
— Борис

1
@Boris - это полезное упражнение.
— маргаритка

1
@daisy , что я говорю, что вы должны выбрать наиболее читаемый синтаксис не операцию , которая находится в 300 наносекунд быстрее (что буквально разница между delи popиз первого набора таймингов выше)
— Борис

Кроме того, эти операции настолько быстры, что эти сроки не являются надежными.
— Борис

46

Если вам нужно удалить много ключей из словаря в одной строке кода, я думаю, что использование 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}

И если вам нужно отлавливать ошибки, когда вы выводите значение, которого нет в словаре, используйте lambda в 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».


42
Это не будет работать в Python 3, потому что mapтеперь друзья ленивы и возвращают итераторы. Использование mapдля побочных эффектов обычно считается плохой практикой; стандартный for ... inцикл будет лучше. Посмотрите Представления И Итераторы вместо Списков для получения дополнительной информации.
— Грег Кример

5
Независимо от вкуса и стиля практики, списки должны работать в Py3 [myDict.pop(i, None) for i in ['a', 'c']], поскольку они предлагают общую альтернативу map(и filter).
— Майкл

@MichaelEkoka Вы не должны использовать списочные выражения для их побочных эффектов, используйте обычный for ... inцикл.
— Борис

@ Борис Ты, наверное, прав. Мой ответ конкретно касается использования map(), которое часто используется для его побочных эффектов. Рекомендованной альтернативой в Python является понимание списка, которое, на мой взгляд, все еще вполне читабельно и когнитивно легко, как однострочный (см. Вопрос). Используемые только для побочных эффектов, обе конструкции действительно приводят к бесполезному списку, который может быть неэффективным. Начиная с Python3, я не знаю встроенной функции, которая может безопасно и элегантно выполнять итерацию по выражению генератора, без дорогостоящего побочного продукта, например loop(d.pop(k) for k in ['a', 'b']).
— Майкл Экока

Меня удивляет, что мой самый голосующий за все время ответ включает в себя некоторые хаки, которые я бы никогда не использовал. Понимание списка (вариант 3) - наименее плохой подход, по моему мнению. Используйте это.
— Марк Максмейстер

20

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

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

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



7

Мы можем удалить ключ из словаря 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

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


1
Не используйте, if myDict.get('one')чтобы проверить, присутствует ли ключ! Сбой, если myDict ['one'] имеет значение false. Кроме того, у дикторов нет внутреннего порядка, поэтому нет смысла упоминать об этом.
— Роб

Диск @Rob упорядочен по порядку вставки, начиная с CPython 3.6 и всех других реализаций Python, начиная с 3.7.
— Борис

4

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

try: 
    del dict[key]

except KeyError: pass

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

my_dict.pop('key', None)

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

Самый быстрый подход заключается в следующем:

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

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


1

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

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}

1

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

items () в сочетании с пониманием 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}

0

Один фильтр на ключ

  • верните «ключ» и удалите его из my_dict, если «ключ» существует в my_dict
  • вернуть 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()
            )
    )
)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.