从字典中删除元素

问题:从字典中删除元素

有没有办法从Python的字典中删除项目?

另外,如何从字典中删除项目以返回副本(即不修改原始内容)?

Is there a way to delete an item from a dictionary in Python?

Additionally, how can I delete an item from a dictionary to return a copy (i.e., not modifying the original)?


回答 0

del语句删除一个元素:

del d[key]

但是,这会使现有字典发生变化,因此对于引用同一实例的其他任何人,字典的内容都会更改。要返回词典,请复制该词典:

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

dict()构造使得浅拷贝。要进行深拷贝,请参阅copy模块


请注意,为每个字典del/ assignment / etc 复制一份。意味着您要从恒定时间变为线性时间,并且还要使用线性空间。对于小命令,这不是问题。但是,如果您打算复制大量大型字典,则可能需要不同的数据结构,例如HAMT(如本答案所述)。

The del statement removes an element:

del d[key]

However, this mutates the existing dictionary so the contents of the dictionary changes for anybody else who has a reference to the same instance. To return a new dictionary, make a copy of the dictionary:

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

The dict() constructor makes a shallow copy. To make a deep copy, see the copy module.


Note that making a copy for every dict del/assignment/etc. means you’re going from constant time to linear time, and also using linear space. For small dicts, this is not a problem. But if you’re planning to make lots of copies of large dicts, you probably want a different data structure, like a HAMT (as described in this answer).


回答 1

pop 使字典变异。

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

如果您想保留原件,则可以将其复印。

pop mutates the dictionary.

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

If you want to keep the original you could just copy it.


回答 2

我认为您的解决方案是最好的方法。但是,如果您需要其他解决方案,则可以使用旧字典中的键来创建新字典,而无需包括指定的键,如下所示:

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

I think your solution is best way to do it. But if you want another solution, you can create a new dictionary with using the keys from old dictionary without including your specified key, like this:

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

回答 3

del语句是你在找什么。如果您有一个名为foo的字典,其键名为“ bar”,则可以从foo中删除“ bar”,如下所示:

del foo['bar']

请注意,这将永久修改正在操作的词典。如果要保留原始词典,则必须事先创建一个副本:

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

dict调用将进行浅表复制。如果要深拷贝,请使用copy.deepcopy

为了方便起见,您可以使用以下方法复制和粘贴:

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

The del statement is what you’re looking for. If you have a dictionary named foo with a key called ‘bar’, you can delete ‘bar’ from foo like this:

del foo['bar']

Note that this permanently modifies the dictionary being operated on. If you want to keep the original dictionary, you’ll have to create a copy beforehand:

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

The dict call makes a shallow copy. If you want a deep copy, use copy.deepcopy.

Here’s a method you can copy & paste, for your convenience:

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

回答 4

有很多不错的答案,但我想强调一件事。

您可以同时使用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。虽然可能由于with函数本身具有复杂性而导致开销,所以delwith incheck的使用快一些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}

There’re a lot of nice answers, but I want to emphasize one thing.

You can use both dict.pop() method and a more generic del statement to remove items from a dictionary. They both mutate the original dictionary, so you need to make a copy (see details below).

And both of them will raise a KeyError if the key you’re providing to them is not present in the dictionary:

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

and

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

You have to take care of this:

by capturing the exception:

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)

and

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)

by performing a check:

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

and

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

but with pop() there’s also a much more concise way – provide the default return value:

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

Unless you use pop() to get the value of a key being removed you may provide anything, not necessary None. Though it might be that using del with in check is slightly faster due to pop() being a function with its own complications causing overhead. Usually it’s not the case, so pop() with default value is good enough.


As for the main question, you’ll have to make a copy of your dictionary, to save the original dictionary and have a new one without the key being removed.

Some other people here suggest making a full (deep) copy with copy.deepcopy(), which might be an overkill, a “normal” (shallow) copy, using copy.copy() or dict.copy(), might be enough. The dictionary keeps a reference to the object as a value for a key. So when you remove a key from a dictionary this reference is removed, not the object being referenced. The object itself may be removed later automatically by the garbage collector, if there’re no other references for it in the memory. Making a deep copy requires more calculations compared to shallow copy, so it decreases code performance by making the copy, wasting memory and providing more work to the GC, sometimes shallow copy is enough.

However, if you have mutable objects as dictionary values and plan to modify them later in the returned dictionary without the key, you have to make a deep copy.

With shallow copy:

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}

With deep copy:

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}

回答 5

…如何从字典中删除项目以返回副本(即不修改原始内容)?

A dict是用于此的错误数据结构。

当然,复制dict并从复制中弹出是可行的,利用理解力构建新dict也是如此,但是所有复制都需要时间-您已经用线性时间操作替换了恒定时间操作。并且所有这些活着的副本立刻占据了空间-每个副本的线性空间。

其他数据结构(例如哈希数组映射尝试)也正是针对这种用例而设计的:添加或删除元素会以对数时间返回一个副本并将其大部分存储与原始共享1个

当然也有一些缺点。性能是对数而不是常数(尽管基数较大,通常为32-128)。而且,尽管您可以使非变异API与相同dict,但“变异” API显然是不同的。而且,最重要的是,Python不附带HAMT电池。2

pyrsistent库是基于HAMT的dict-replacement(以及各种其他类型)的Python相当可靠的实现。它甚至还有一个漂亮的Evolutioner API,用于尽可能平滑地将现有的变异代码移植到持久代码中。但是,如果您想明确地表示要返回副本而不是进行变异,则可以像这样使用它:

>>> 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')正是这个问题所要的。

如果您有可变的数据结构(例如)dictlist嵌入到中pmap,则仍然会出现别名问题-您只能通过将pmaps和pvectors 嵌入所有位置来实现不可变,以解决此问题。


1. HAMT在Scala,Clojure和Haskell等语言中也很流行,因为它们在无锁编程和软件事务存储中的表现非常好,但是在Python中它们都不重要。

2.事实上,在一个STDLIB HAMT,在执行中使用contextvars较早撤消的PEP解释了原因。但这是库的隐藏实现细节,而不是公共集合类型。

… how can I delete an item from a dictionary to return a copy (i.e., not modifying the original)?

A dict is the wrong data structure to use for this.

Sure, copying the dict and popping from the copy works, and so does building a new dict with a comprehension, but all that copying takes time—you’ve replaced a constant-time operation with a linear-time one. And all those copies alive at once take space—linear space per copy.

Other data structures, like hash array mapped tries, are designed for exactly this kind of use case: adding or removing an element returns a copy in logarithmic time, sharing most of its storage with the original.1

Of course there are some downsides. Performance is logarithmic rather than constant (although with a large base, usually 32-128). And, while you can make the non-mutating API identical to dict, the “mutating” API is obviously different. And, most of all, there’s no HAMT batteries included with Python.2

The pyrsistent library is a pretty solid implementation of HAMT-based dict-replacements (and various other types) for Python. It even has a nifty evolver API for porting existing mutating code to persistent code as smoothly as possible. But if you want to be explicit about returning copies rather than mutating, you just use it like this:

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

That d3 = d1.remove('a') is exactly what the question is asking for.

If you’ve got mutable data structures like dict and list embedded in the pmap, you’ll still have aliasing issues—you can only fix that by going immutable all the way down, embedding pmaps and pvectors.


1. HAMTs have also become popular in languages like Scala, Clojure, Haskell because they play very nicely with lock-free programming and software transactional memory, but neither of those is very relevant in Python.

2. In fact, there is an HAMT in the stdlib, used in the implementation of contextvars. The earlier withdrawn PEP explains why. But this is a hidden implementation detail of the library, not a public collection type.


回答 6

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

结果: d = {1: 2, '2': 3}

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

Result: d = {1: 2, '2': 3}


回答 7

只需调用del d [‘key’]。

但是,在生产中,始终最好检查d中是否存在“密钥”。

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

Simply call del d[‘key’].

However, in production, it is always a good practice to check if ‘key’ exists in d.

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

回答 8

不,除了

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

但是,通常仅创建略有变化的字典的副本可能不是一个好主意,因为这将导致相对较大的内存需求。通常最好记录旧字典(如果需要的话),然后对其进行修改。

No, there is no other way than

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

However, often creating copies of only slightly altered dictionaries is probably not a good idea because it will result in comparatively large memory demands. It is usually better to log the old dictionary(if even necessary) and then modify it.


回答 9

# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 5)
# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 5)

回答 10

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

这不会进行任何错误处理,它假定键在字典中,您可能需要先检查一下,raise如果没有

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

this doesn’t do any error handling, it assumes the key is in the dict, you might want to check that first and raise if its not


回答 11

这里是一种顶层设计方法:

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}

希望有帮助!

Here a top level design approach:

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

I’m passing the dictionary and the key I want into my function, validates if it’s a dictionary and if the key is okay, and if both exist, removes the value from the dictionary and prints out the left-overs.

Output: {'B': 55, 'A': 34}

Hope that helps!


回答 12

下面的代码段绝对会帮助您,我在每一行中添加了注释,这将有助于您理解代码。

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}

Below code snippet will help you definitely, I have added comments in each line which will help you in understanding the code.

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

or you can also use dict.pop()

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

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

or the better approach is

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}

回答 13

这是使用列表理解的另一个变体:

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

该方法基于本文的答案:一种 有效的方法来从字典中删除带有空字符串的键

Here’s another variation using list comprehension:

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

The approach is based on an answer from this post: Efficient way to remove keys with empty strings from a dict


回答 14

    species = {'HI': {'1': (1215.671, 0.41600000000000004),
  '10': (919.351, 0.0012),
  '1025': (1025.722, 0.0791),
  '11': (918.129, 0.0009199999999999999),
  '12': (917.181, 0.000723),
  '1215': (1215.671, 0.41600000000000004),
  '13': (916.429, 0.0005769999999999999),
  '14': (915.824, 0.000468),
  '15': (915.329, 0.00038500000000000003),
 'CII': {'1036': (1036.3367, 0.11900000000000001), '1334': (1334.532, 0.129)}}

以下代码将复制字典species并删除不在目录中的项目trans_HI

trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
    if transition not in trans_HI:
        species['HI'].pop(transition)
    species = {'HI': {'1': (1215.671, 0.41600000000000004),
  '10': (919.351, 0.0012),
  '1025': (1025.722, 0.0791),
  '11': (918.129, 0.0009199999999999999),
  '12': (917.181, 0.000723),
  '1215': (1215.671, 0.41600000000000004),
  '13': (916.429, 0.0005769999999999999),
  '14': (915.824, 0.000468),
  '15': (915.329, 0.00038500000000000003),
 'CII': {'1036': (1036.3367, 0.11900000000000001), '1334': (1334.532, 0.129)}}

The following code will make a copy of dict species and delete items which are not in trans_HI

trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
    if transition not in trans_HI:
        species['HI'].pop(transition)