Как удалить ключ из словаря 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']], поскольку они предлагают общую альтернативу mapfilter).
Майкл

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