Удаление элемента из справочника

есть ли способ удалить элемент из словаря в Python?

кроме того, как я могу удалить элемент из словаря, чтобы вернуть копию (т. е., не изменяя оригинал)?

14 ответов


на del сообщении удаляет элемент:

del d[key]

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

def removekey(d, key):
    r = dict(d)
    del r[key]
    return r

на dict() конструктор делает мелкая копия. Чтобы сделать глубокую копию, см. copy модуль.


обратите внимание, что создание копии для каждого dict del / назначение / etc. означает, что вы переходите от постоянного времени к линейному времени, а также используете линейное пространство. Для маленьких диктов это не проблема. Но если вы планируете сделать много копий больших диктов, вам, вероятно, нужна другая структура данных, например HAMT (как описано в ответ).


pop мутирует словарь.

 >>>lol = {"hello":"gdbye"}
 >>>lol.pop("hello")
    'gdbye'
 >>> lol
     {}

Если вы хотите сохранить оригинал, вы можете просто скопировать его.


Я думаю, что ваше решение-лучший способ сделать это. Но если вы хотите другое решение, вы можете создать новый словарь с использованием ключей из старого словаря без включения указанного ключа, например:

>>> a
{0: 'zero', 1: 'one', 2: 'two', 3: 'three'}
>>> {i:a[i] for i in a if i!=0}
{1: 'one', 2: 'two', 3: 'three'}

на заявление-дель - это то, что вы ищете. Если у вас есть словарь с именем foo с ключом "bar", вы можете удалить "bar" из foo следующим образом:

del foo['bar']

обратите внимание,что это постоянно изменяет словарь, работающий на. Если вы хотите сохранить оригинальный словарь, вам придется создать копию заранее:

>>> foo = {'bar': 'baz'}
>>> fu = dict(foo)
>>> del foo['bar']
>>> print foo
{}
>>> print fu
{'bar': 'baz'}

на dict call делает мелкую копию. Если вам нужна глубокая копия, используйте copy.deepcopy.

вот метод, который вы можете скопировать и вставить, для вашего удобства:

def minus_key(key, dictionary):
    shallow_copy = dict(dictionary)
    del shallow_copy[key]
    return shallow_copy

есть много хороших ответов, но я хочу подчеркнуть одну вещь.

можно использовать dict.pop() метод и более универсальная del сообщении для удаления элементов из словаря. Они оба мутируют исходный словарь, поэтому вам нужно сделать копию (см. подробности ниже).

и оба они поднимутKeyError если ключ вы обеспечиваете их нет в словарь:

key_to_remove = "c"
d = {"a": 1, "b": 2}
del d[key_to_remove]  # Raises `KeyError: 'c'`

и

key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove)  # Raises `KeyError: 'c'`

вы должны позаботиться об этом:

захватив исключение:

key_to_remove = "c"
d = {"a": 1, "b": 2}
try:
    del d[key_to_remove]
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

и

key_to_remove = "c"
d = {"a": 1, "b": 2}
try:
    d.pop(key_to_remove)
except KeyError as ex:
    print("No such key: '%s'" % ex.message)

проведя проверку:

key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
    del d[key_to_remove]

и

key_to_remove = "c"
d = {"a": 1, "b": 2}
if key_to_remove in d:
    d.pop(key_to_remove)

но с pop() существует также гораздо более краткий способ-укажите возвращаемое значение по умолчанию:

key_to_remove = "c"
d = {"a": 1, "b": 2}
d.pop(key_to_remove, None)  # No `KeyError` here

если вы не используете pop() чтобы получить значение удаляемого ключа, вы можете предоставить что угодно, не обязательно None. Хотя это может быть использование del С in проверка немного быстрее из-за pop() быть функцией со своими собственными усложнениями причиняя накладные расходы. Обычно это не так, так что pop() со значением по умолчанию является достаточно хорошим.


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

некоторые другие люди здесь предлагают сделать полную (глубокую) копию с copy.deepcopy(), что может быть излишним," нормальной " (мелкой) копией, используя copy.copy() или dict.copy(), может быть достаточно. Словарь хранит ссылку на объект в качестве значения для ключа. Поэтому, когда вы удаляете ключ из словаря, эта ссылка удаляется, а не объект, на который ссылаются. Сам объект может быть удален позже автоматически сборщиком мусора, если нет других ссылок на него в памяти. Для создания глубокой копии требуется больше вычислений по сравнению с мелкой копией, поэтому она снижает производительность кода, делая копию, тратя память и предоставляя больше работы GC, иногда достаточно мелкой копии.

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

С мелкой копией:

def get_dict_wo_key(dictionary, key):
    """Returns a **shallow** copy of the dictionary without a key."""
    _dict = dictionary.copy()
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3], "b": 2, "c": 3}
key_to_remove = "c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3], "b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3, 100], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3, 100], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2222}

С глубоким копия:

from copy import deepcopy


def get_dict_wo_key(dictionary, key):
    """Returns a **deep** copy of the dictionary without a key."""
    _dict = deepcopy(dictionary)
    _dict.pop(key, None)
    return _dict


d = {"a": [1, 2, 3], "b": 2, "c": 3}
key_to_remove = "c"

new_d = get_dict_wo_key(d, key_to_remove)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3], "b": 2}
new_d["a"].append(100)
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2}
new_d["b"] = 2222
print(d)  # {"a": [1, 2, 3], "b": 2, "c": 3}
print(new_d)  # {"a": [1, 2, 3, 100], "b": 2222}

d = {1: 2, '2': 3, 5: 7}
del d[5]
print 'd = ', d

результат: d = {1: 2, '2': 3}


просто вызовите del d ['key'].

однако в производстве всегда рекомендуется проверять, существует ли "ключ" в d.

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

нет, нет другого способа, кроме

def dictMinus(dct, val):
   copy = dct.copy()
   del copy[val]
   return copy

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


>>> def delete_key(dict, key):
...     del dict[key]
...     return dict
... 
>>> test_dict = {'one': 1, 'two' : 2}
>>> print delete_key(test_dict, 'two')
{'one': 1}
>>>

это не делает никакой обработки ошибок, он предполагает, что ключ находится в dict, вы можете сначала проверить это и raise, если не


... как удалить элемент из словаря, чтобы вернуть копию (т. е. не изменять оригинал)?

A dict неправильная структура данных для использования для этого.

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

другие структуры данных, такие как хэш-массив сопоставляется нах, предназначены именно для такого случая использования: добавление или удаление элемента возвращает копию в логарифмическом времени, разделяя большую часть своего хранилища с оригиналом.1

конечно есть некоторые минусы. Производительность логарифмическая, а не постоянная (хотя с большой базой, обычно 32-128). И, хотя вы можете сделать не мутирующий API идентичным к dict," мутирующий " API, очевидно, отличается. И, самое главное, в Python нет батарей HAMT.2

на pyrsistent библиотека-довольно солидная реализация дикт-замен на основе HAMT (и различных других типов) для Python. Он даже имеет изящный API-интерфейс Evolver с для переноса существующего мутирующего кода в постоянный код как можно более плавно. Но если вы хотите быть явным о возвращении копий, а не мутируя, вы просто используете его так:

>>> from pyrsistent import m
>>> d1 = m(a=1, b=2)
>>> d2 = d1.set('c', 3)
>>> d3 = d1.remove('a')
>>> d1
pmap({'a': 1, 'b': 2})
>>> d2
pmap({'c': 3, 'a': 1, 'b': 2})
>>> d3
pmap({'b': 2})

это d3 = d1.remove('a') - это именно то, что спрашивается.

если у вас есть изменяемые структуры данных, такие как dict и list встроена в pmap, у вас все равно будут проблемы с псевдонимами-вы можете исправить это, только пройдя неизменный путь вниз, встраивая pmaps и pvectors.


1. HAMTs также стали популярными на таких языках, как Scala, Clojure, Haskell, потому что они играют очень хорошо с блокировкой программирования и программного обеспечения транзакционной памяти, но ни один из них не очень актуален в Python.

2. На самом деле, там is HAMT в stdlib, используемый в реализации contextvars. ранее отозванный PEP объясняет, почему. но это скрытая деталь реализации библиотеки, а не тип общедоступной коллекции.


здесь подход к дизайну верхнего уровня:

def eraseElement(d,k):
    if isinstance(d, dict):
        if k in d:
            d.pop(k)
            print(d)
        else:
            print("Cannot find matching key")
    else:
        print("Not able to delete")


exp = {'A':34, 'B':55, 'C':87}
eraseElement(exp, 'C')

Я передаю словарь и ключ, который я хочу в свою функцию, проверяет, является ли это словарем, и если ключ в порядке, и если оба существуют, удаляет значение из словаря и распечатывает левые.

выход: {'B': 55, 'A': 34}

надеюсь, что это поможет!


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

ret_val = ('key' in body and body.pop('key')) or 5

ниже фрагмент кода поможет вам определенно, я добавил комментарии в каждой строке, которые помогут вам в понимании кода.

def execute():
   dic = {'a':1,'b':2}
   dic2 = remove_key_from_dict(dic, 'b')  
   print(dict2)           # {'a': 1}
   print(dict)            # {'a':1,'b':2}

def remove_key_from_dict(dictionary_to_use, key_to_delete):
   copy_of_dict = dict(dictionary_to_use)     # creating clone/copy of the dictionary
   if key_to_delete in copy_of_dict :         # checking given key is present in the dictionary
       del copy_of_dict [key_to_delete]       # deleting the key from the dictionary 
   return copy_of_dict                        # returning the final dictionary

или вы также можете использовать dict.pop ()

d = {"a": 1, "b": 2}

res = d.pop("c")  # No `KeyError` here
print (res)       # this line will not execute

или лучше

res = d.pop("c", "key not found")
print (res)   # key not found
print (d)     # {"a": 1, "b": 2}

res = d.pop("b", "key not found")
print (res)   # 2
print (d)     # {"a": 1}

вот еще один вариант использования понимания списка:

original_d = {'a': None, 'b': 'Some'}
d = dict((k,v) for k, v in original_d.iteritems() if v)
# result should be {'b': 'Some'}

подход основан на ответе на этот пост: эффективный способ удаления ключей с пустыми строками из dict