如何从 Python 中的字典中删除项目?
在不修改原始字典的情况下,如何获得另一个删除项目的字典?
pop
method 更改字典就地。因此,它改变了从调用者传递给“帮助函数”的字典的reference。所以“辅助函数”不需要返回任何东西,因为调用者中对字典的原始引用已经被改变了。如果您不需要它,请不要将 dict.pop()
的返回值分配给任何东西。例如:do stuff with my_dict; my_dict.pop(my_key, None); do more stuff with my_dict # now doesn't have my_key
。如果需要,使用 deepcopy(my_dict)
。
d.pop()
,所以我固定标题问细节中指定的问题。
d.pop(key)
。但是,如果有任何东西修改了浅拷贝,那么您就有一个 well-known problem with aliasing。如果你告诉我们更广泛的背景,它会有所帮助。 (还有其他任何东西修改过 dict 值吗?您是否试图破坏性地迭代列表?如果没有,那是什么?)
del
statement 删除一个元素:
del d[key]
请注意,这会改变现有字典,因此字典的内容对于引用同一实例的任何其他人都会发生变化。要返回新字典,请复制字典:
def removekey(d, key):
r = dict(d)
del r[key]
return r
dict()
构造函数制作一个浅拷贝。要制作深层副本,请参阅 copy
module。
请注意,为每个字典 del
/assignment/etc 制作一份副本。意味着您正在从恒定时间变为线性时间,并且还使用线性空间。对于小型听写,这不是问题。但是,如果您打算制作大量大型 dicts 的副本,您可能需要不同的数据结构,例如 HAMT(如 this answer 中所述)。
pop
改变字典。
>>> lol = {"hello": "gdbye"}
>>> lol.pop("hello")
'gdbye'
>>> lol
{}
如果你想保留原件,你可以复制它。
pop
返回“弹出”的值,这允许您出于任何其他原因使用此值。如果它不是更“Pythonic”,我会说这看起来更好,当然:)。这不是一个字典,但它对两者的工作方式相同:github.com/ivanlmj/python-prototypes/blob/master/3.4/…
pop
提供一个默认值,当字典中缺少键时将返回该默认值。当您需要删除一些键但其中一些可能丢失时,这很好; del
在这种情况下会抛出 KeyError
。
我认为您的解决方案是最好的方法。但是,如果您想要另一个解决方案,您可以使用旧字典中的键创建一个新字典,而不包括您指定的键,如下所示:
>>> 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:a[i] for i in a if i not in [0, 1, 2]}
如果您想删除多个元素。
{k:v for k,v in a.items() if k != 0}
会更好。
**kwargs
,some_function(**{k:v for k,v in some_dict.items() if k not 'some_key'})
有很多不错的答案,但我想强调一件事。
您可以使用 dict.pop()
方法和更通用的 del
statement 从字典中删除项目。它们都改变了原始字典,因此您需要制作副本(请参阅下面的详细信息)。
如果您提供给他们的密钥不在字典中,他们都会引发 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}
del statement 就是您要查找的内容。如果你有一个名为 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
>>>
?是的,python-doc 包含很多这样的东西。但是这样的代码不方便复制粘贴。我很困惑...
>>>
在 cli 模式下模仿 python 的侦听符号
>>>
。是的,它是 REPL 风格的,但让我们坦率地说:只有一个人写过这个样本,而 1000 人读过这个。我认为,以易于复制和运行的方式编写示例会很棒。我不喜欢手动删除这个尖括号。或者逐行复制..所以我不明白:为什么这个角度仍然存在)))可能是我不知道什么?
...我如何从字典中删除一个项目以返回一个副本(即,不修改原件)?
dict
是用于此的错误数据结构。
当然,复制 dict 并从副本中弹出是有效的,用理解构建一个新的 dict 也是如此,但是所有复制都需要时间——你已经用线性时间操作替换了恒定时间操作。所有这些活着的副本同时占用空间——每个副本的线性空间。
其他数据结构(例如 hash array mapped tries)正是为这种用例而设计的:添加或删除元素会返回一个对数时间的副本,与原始元素共享大部分存储空间。 1
当然也有一些缺点。性能是对数而不是常数(尽管基数很大,通常为 32-128)。而且,虽然您可以使非变异 API 与 dict
相同,但“变异”API 显然不同。而且,最重要的是,Python 不包含 HAMT 电池。2
pyrsistent
库是 Python 的基于 HAMT 的 dict-replacements(和各种其他类型)的非常可靠的实现。它甚至有一个漂亮的 evolver 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')
正是问题所要求的。
如果您在 pmap
中嵌入了 dict
和 list
等可变数据结构,您仍然会遇到别名问题 — 您只能通过一直不可变、嵌入 pmap
和pvector
秒。
1. HAMT 在 Scala、Clojure、Haskell 等语言中也很流行,因为它们在无锁编程和软件事务内存方面表现得非常好,但这些都与 Python 无关。
<子> 2。事实上,在标准库中有一个 HAMT,用于 contextvars
的实现。 The earlier withdrawn PEP explains why. 但这是库的隐藏实现细节,而不是公共集合类型。
d = {1: 2, '2': 3, 5: 7}
del d[5]
print 'd = ', d
结果:d = {1: 2, '2': 3}
只需调用 del d['key']。
但是,在生产中,检查 d 中是否存在“key”始终是一个好习惯。
if 'key' in d:
del d['key']
try-except
块中的键。至少,这将是一个原子操作;)
d.pop('key', None)
,它是 oneliner。但实际的问题是关于没有一键获取字典,而不是修改字典。所以 comprehensions - 在这里是一个不错的选择;)
不,没有别的办法
def dictMinus(dct, val):
copy = dct.copy()
del copy[val]
return copy
但是,经常创建仅略微更改的字典的副本可能不是一个好主意,因为它会导致相对较大的内存需求。通常最好记录旧字典(如果有必要的话)然后修改它。
# mutate/remove with a default
ret_val = body.pop('key', 5)
# no mutation with a default
ret_val = body.get('key', 5)
这里有一个顶层设计方法:
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}
希望有帮助!
>>> 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
del test_dict[key]
有何不同?
下面的代码片段肯定会帮助你,我在每一行都添加了注释,这将帮助你理解代码。
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'}
该方法基于这篇文章的答案:Efficient way to remove keys with empty strings from a dict
对于 Python 3,这是
original_d = {'a': None, 'b': 'Some'}
d = dict((k,v) for k, v in original_d.items() if v)
print(d)
if v
更改为 if k is not 'a'
即可回答操作。但我认为这不是一种有效的方法,这会删除 O(n) 中的元素,而不是像 pop 或 del 那样删除 O(log n) 中的元素。
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)}}
以下代码将复制 dict species
并删除不在 trans_HI
中的项目
trans_HI=['1025','1215']
for transition in species['HI'].copy().keys():
if transition not in trans_HI:
species['HI'].pop(transition)
解决方案1:删除
info = {'country': 'Iran'}
country = info.pop('country') if 'country' in info else None
解决方案2:不删除
info = {'country': 'Iran'}
country = info.get('country') or None
可以试试我的方法。在一条线上。
yourList = [{'key':'key1','version':'1'},{'key':'key2','version':'2'},{'key':'key3','version':'3'}]
resultList = [{'key':dic['key']} for dic in yourList if 'key' in dic]
print(resultList)
dict
,它会给您一个错误:RuntimeError: dictionary changed size during iteration
pop
方法实际上是做什么的呢?它不是更pythonic吗? (是dict的方法,不是特殊的保留字)?