2553

Is there a one-line way of deleting a key from a dictionary without raising a KeyError?

if 'key' in my_dict:
    del my_dict['key']
Mateen Ulhaq
  • 21,459
  • 16
  • 82
  • 123
Tony
  • 34,025
  • 9
  • 47
  • 82
  • 32
    Benchmark script for the various methods proposed in the answers to this question: https://gist.github.com/zigg/6280653 – zigg Aug 20 '13 at 12:19
  • 1
    Does this answer your question? [Delete an element from a dictionary](https://stackoverflow.com/questions/5844672/delete-an-element-from-a-dictionary) – Abu Shoeb Jan 16 '21 at 21:20

16 Answers16

4080

To delete a key regardless of whether it is in the dictionary, use the two-argument form of dict.pop():

my_dict.pop('key', None)

This will return my_dict[key] if key exists in the dictionary, and None otherwise. If the second parameter is not specified (i.e. my_dict.pop('key')) and key does not exist, a KeyError is raised.

To delete a key that is guaranteed to exist, you can also use:

del my_dict['key']

This will raise a KeyError if the key is not in the dictionary.

Ann Zen
  • 25,080
  • 7
  • 31
  • 51
Sven Marnach
  • 530,615
  • 113
  • 910
  • 808
  • 241
    Sometimes an advantage of using `pop()` over `del`: it returns the value for that key. This way you can get and delete an entry from a dict in one line of code. – kratenko Aug 18 '13 at 12:21
  • 10
    In the question it is not required to keep the value. This would only add unneeded complexity. The answer from @zigg (below) is much better. – Salvatore Cosentino Jun 14 '17 at 02:05
  • 16
    @SalvatoreCosentino I can't follow your argument. How is the code in this answer more complex than the code in in the other answer? – Sven Marnach Jun 15 '17 at 13:52
  • 2
    Hello @SvenMarnach, to 1) The answer below is more elegant in my opinion (e.g., handling the exception) 2) using 'pop' in most programming languages (and data structures) is used when you want to store the deleted value, and the question only asks about deleting a key. Returning a value that is never used would be simply unefficient. – Salvatore Cosentino Jun 15 '17 at 15:44
  • 51
    @SalvatoreCosentino No, ignoring the return value of a function is not inefficient at all. Quite the opposite – this solution is much faster than the `try`/`except` solution if the key does not exist. You might find one or the other easier to read, which is fine. Both are idiomatic Python, so choose whatever you prefer. But claiming that this answer is more complex or inefficient simply makes no sense. – Sven Marnach Jun 15 '17 at 18:44
  • A problem with this approach is that it returns the value of `key`, and not the original dict. So, `{'a':1, 'b':2}.pop('b')` returns `2` instead of `{'a':1}` – user5359531 Aug 01 '18 at 17:47
  • 8
    @user5359531 I don't understand. How is this a problem? None of the methods on Python's built-in types returns `self`, so it would be rather surprising if this one did. – Sven Marnach Aug 02 '18 at 10:09
  • when trying to use this feature inside a list-comprehension, which is a pretty typical use case for one-liners in Python. Transforming one list of dicts into another where some keys have been removed. – user5359531 Aug 03 '18 at 17:29
  • 6
    @user5359531 You should generally avoid list comprehensions with side effects, since they are confusing. If `dict.pop()` returned the original dict, then `b = [d.pop("key") for d in a]` would modify _both_ lists, `a` and `b`, since they would both share the same dictionary objects. This is part of the reason why Python has the convention that mutating methods don't have a return value. (In fact, `dict.pop()` is an exception of this convention, but it does not violate the spirit of the convention.) – Sven Marnach Aug 03 '18 at 17:48
  • 6
    @user5359531 If you want to mutate a list of dictionaries in place, use a for loop: `for d in a: d.pop("key", None)`. If you want to keep the original dictionaries unchanged, copy them first: `b = [d.copy() for d in a]`. – Sven Marnach Aug 03 '18 at 17:50
  • useful use case: creating hierarchy from a flat dict as in `new_dict = {my_dict.pop('key_to_promote'): my_dict}` – matanster May 23 '20 at 08:36
  • The equivalent for the `set` datastructure is the `discard` operation. For e.g `my_set.discard(k)` will remove k without raising KeyError, whereas `my_set.remove(k) ` will raise KeyError if `k` is not present in the set. – Ambareesh Aug 22 '20 at 15:07
424

Specifically to answer "is there a one line way of doing this?"

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

...well, you asked ;-)

You should consider, though, that this way of deleting an object from a dict is not atomic—it is possible that 'key' may be in my_dict during the if statement, but may be deleted before del is executed, in which case del will fail with a KeyError. Given this, it would be safest to either use dict.pop or something along the lines of

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

which, of course, is definitely not a one-liner.

Boris Verkhovskiy
  • 10,733
  • 7
  • 77
  • 79
zigg
  • 19,044
  • 7
  • 35
  • 54
  • 33
    Yeah, `pop` is a definitely more concise, though there is one key advantage of doing it this way: it's immediately clear what it's doing. – zigg Jul 01 '12 at 16:30
  • 6
    The `try/except` statement is more expensive. Raising an exception is slow. – Chris Barker Aug 20 '13 at 05:01
  • 19
    @ChrisBarker I've found if the key exists, `try` is marginally faster, though if it doesn't, `try` is indeed a good deal slower. `pop` is fairly consistent but slower than all but `try` with a non-present key. See https://gist.github.com/zigg/6280653. Ultimately, it depends on how often you expect the key to actually be in the dictionary, and whether or not you need atomicity—and, of course, whether or not you're engaging in premature optimization ;) – zigg Aug 20 '13 at 12:18
  • 10
    I believe the value of clarity should not be overlooked. +1 for this. – Juan Carlos Coto Jun 30 '14 at 21:15
  • 3
    regarding expense of try/except, you can also go ```if 'key' in mydict: #then del...```. I needed to pull out a key/val from a dict to parse correctly, pop was not a perfect solution. – Marc Jul 09 '15 at 18:00
  • 1
    @datamafia Like all `if k in d` solutions, though, that's not atomic and the `del` may fail. Why didn't `pop` work for you? – zigg Jul 14 '15 at 13:25
  • @zigg I had a wonky data structure, in short I needed to order dict via a key/val pair nested in dict. So I used ```if key in``` to qualify if the trouble making key is in dict, copy to a temp dict, perform lambda/list comp ordering of dict, then add the value back in. Pop and del work the same in that instance. The conditional qualifier allowed the key/val to be placed in temp dict for ordering to work. This was a work around for some brownfield code, not perfect but we moved on. ```pop()``` would have also worked, I like the del verbosity. Try/catch can be expensive. – Marc Jul 14 '15 at 15:42
  • Try catch is the "correct way" to do it. it is not awkward. – PythonTester Mar 11 '16 at 16:01
  • 1
    @Marc if you need to process a key:value pair, use `popitem()` instead. Put it in a while loop to consume the entire dict. – Gloweye Aug 29 '18 at 08:14
  • @ChrisBarker Python is a lang intended to manage exceptions, they are only marginally slower than other options see: https://stackoverflow.com/questions/2522005/cost-of-exception-handlers-in-python – juan Isaza Mar 05 '21 at 16:00
183

It took me some time to figure out what exactly my_dict.pop("key", None) is doing. So I'll add this as an answer to save others googling time:

pop(key[, default])

If key is in the dictionary, remove it and return its value, else return default. If default is not given and key is not in the dictionary, a KeyError is raised.

Documentation

Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Akavall
  • 76,296
  • 45
  • 192
  • 242
75

del my_dict[key] is slightly faster than my_dict.pop(key) for removing a key from a dictionary when the key exists

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

But when the key doesn't exist if key in my_dict: del my_dict[key] is slightly faster than my_dict.pop(key, None). Both are at least three times faster than del in a try/except statement:

>>> 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
Boris Verkhovskiy
  • 10,733
  • 7
  • 77
  • 79
Peter Smit
  • 1,504
  • 13
  • 22
62

If you need to remove a lot of keys from a dictionary in one line of code, I think using map() is quite succinct and Pythonic readable:

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}

And if you need to catch errors where you pop a value that isn't in the dictionary, use lambda inside map() like this:

map(lambda x: myDict.pop(x,None), ['a', 'c', 'e'])
[1, 3, None] # pop returns
>>> myDict
{'b': 2, 'd': 4}

or in python3, you must use a list comprehension instead:

[myDict.pop(x, None) for x in ['a', 'c', 'e']]

It works. And 'e' did not cause an error, even though myDict did not have an 'e' key.

Marc Maxmeister
  • 3,607
  • 2
  • 33
  • 47
  • 45
    This will not work in Python 3 because `map` and friends are now lazy and return iterators. Using `map` for side-effects is generally considered poor practice; a standard `for ... in` loop would be better. See [Views And Iterators Instead Of Lists](https://docs.python.org/3.0/whatsnew/3.0.html#views-and-iterators-instead-of-lists) for more information. – Greg Krimer Nov 07 '15 at 16:31
  • 5
    Regardless of taste and practice style, list comprehensions should still work in Py3 `[myDict.pop(i, None) for i in ['a', 'c']]`, as they offer a general alternative to `map` (and `filter`). – Michael Ekoka Oct 22 '17 at 08:48
  • 1
    @MichaelEkoka you shouldn't use list comprehensions for their side effects, use a regular `for ... in` loop. – Boris Verkhovskiy Apr 03 '20 at 08:32
  • 1
    @Boris You're probably right. My answer is specifically pertaining to using `map()`, which is often used for its side-effects. The recommended alternative in Python *is* the list comprehension, which in my opinion is still quite readable and cognitively light as a one-liner (see question). Used only for their side-effects, both constructs indeed result in a useless list, which can be inefficient. As of Python3, I'm not aware of a built-in function that can safely and elegantly iterate through a generator expression, without a costly byproduct e.g. `loop(d.pop(k) for k in ['a', 'b'])`. – Michael Ekoka Apr 07 '20 at 14:06
  • I am amused that my all-time most upvoted answer includes some hacks I would never use. The list comprehension (option 3) is the least bad approach, in my opinion. Use that one. – Marc Maxmeister Apr 08 '20 at 03:20
  • 1
    @MichaelEkoka the "builtin function" is a for loop: `for k in ['a', 'b']: d.pop(k)`. Why do you need a different way to do it? If you need it to take up only one line that badly then you can put the second part of the for loop on the same line. – Boris Verkhovskiy May 04 '20 at 14:18
  • @Boris As I said, my answer pertains *specifically* to using `map()` (and `filter()`), meaning that if you have to use any of those two, you might as well just use a list comprehension. I also acknowledge that both list comprehension and `map()` are wasteful as they produce an unnecessary list as a byproduct. It remains that their more functional syntax is still appreciated and desired by many programmers (e.g. https://stackoverflow.com/q/1080026/56974). It's a matter of style. Unfortunately Python does not offer a builtin functional way to loop and execute without byproduct. – Michael Ekoka May 04 '20 at 15:18
55

You can use a dictionary comprehension to create a new dictionary with that key removed:

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

You can delete by conditions. No error if key doesn't exist.

Boris Verkhovskiy
  • 10,733
  • 7
  • 77
  • 79
Shameem
  • 2,374
  • 15
  • 20
  • 4
    This answer is different than the others because it has no side-effects (it does not mutate the original dictionary). – Jeff D. White Aug 05 '20 at 23:33
  • 2
    While this is probably the way I would do it aswell, this makes a whole new dictionary in memory, copying (references to) objects to the new dictionary. It then saves it onto the old name. For big dictionaries this can take some time. `del dict[key]` or `dict.pop(key)` will be faster in all cases. – mazunki Nov 20 '20 at 19:51
  • `del` and `pop` are faster, but sometimes you just **don't want** to modify the original dictionary. It would make more sense if in the example above, the comprehension result was assigned to another variable. – Ramon Dias May 17 '22 at 22:06
19

Using the "del" keyword:

del dict[key]
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
Sarthak Gupta
  • 784
  • 11
  • 22
11

We can delete a key from a Python dictionary by the some of the following approaches.

Using the del keyword; it's almost the same approach like you did though -

 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}

Or

We can do like the following:

But one should keep in mind that, in this process actually it won't delete any key from the dictionary rather than making a specific key excluded from that dictionary. In addition, I observed that it returned a dictionary which was not ordered the same as myDict.

myDict = {'one': 100, 'two': 200, 'three': 300, 'four': 400, 'five': 500}
{key:value for key, value in myDict.items() if key != 'one'}

If we run it in the shell, it'll execute something like {'five': 500, 'four': 400, 'three': 300, 'two': 200} - notice that it's not the same ordered as myDict. Again if we try to print myDict, then we can see all keys including which we excluded from the dictionary by this approach. However, we can make a new dictionary by assigning the following statement into a variable:

var = {key:value for key, value in myDict.items() if key != 'one'}

Now if we try to print it, then it'll follow the parent order:

print(var) # {'two': 200, 'three': 300, 'four': 400, 'five': 500}

Or

Using the pop() method.

myDict = {'one': 100, 'two': 200, 'three': 300}
print(myDict)

if myDict.get('one') : myDict.pop('one')
print(myDict)  # {'two': 200, 'three': 300}

The difference between del and pop is that, using pop() method, we can actually store the key's value if needed, like the following:

myDict = {'one': 100, 'two': 200, 'three': 300}
if myDict.get('one') : var = myDict.pop('one')
print(myDict) # {'two': 200, 'three': 300}
print(var)    # 100

Fork this gist for future reference, if you find this useful.

M.Innat
  • 13,008
  • 6
  • 38
  • 74
  • 6
    Don't use `if myDict.get('one')` to check if a key is present! It fails if myDict['one'] has a falsey value. Also, dicts don't have an inherent order, so it doesn't make sense to mention it. – Rob Feb 28 '19 at 08:35
  • @Rob dicts are ordered by insertion order starting with CPython 3.6 and all other Python implementations starting with 3.7. – Boris Verkhovskiy Apr 03 '20 at 08:29
9

You can use exception handling if you want to be very verbose:

try: 
    del dict[key]

except KeyError: pass

This is slower, however, than the pop() method, if the key doesn't exist.

my_dict.pop('key', None)

It won't matter for a few keys, but if you're doing this repeatedly, then the latter method is a better bet.

The fastest approach is this:

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

But this method is dangerous because if 'key' is removed in between the two lines, a KeyError will be raised.

Alec
  • 7,110
  • 7
  • 28
  • 53
6

Dictionary data type has a method called dict_name.pop(item) and this can be used to delete a key:value pair from a dictionary.

a={9:4,2:3,4:2,1:3}
a.pop(9)
print(a)

This will give the output as:

{2: 3, 4: 2, 1: 3}

This way you can delete an item from a dictionary in one line.

Anshika Singh
  • 836
  • 7
  • 20
5

Another way is by using items() + dict comprehension.

items() coupled with dict comprehension can also help us achieve the task of key-value pair deletion, but it has the drawback of not being an in place dict technique. Actually a new dict if created except for the key we don’t wish to include.

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

Output:

dictionary before performing remove is : {'sai': 22, 'kiran': 21, 'vinod': 21, 'sangam': 21}
dictionary after remove is : {'sai': 22, 'kiran': 21, 'sangam': 21}
Peter Mortensen
  • 30,030
  • 21
  • 100
  • 124
  • this doesn't actually do what is asked - it creates a new dict with the unwanted keys removed. Furthermore, iterating over all keys to delete one is doing an O(1) operation in O(N) time. – anon01 May 04 '21 at 22:20
5

just create a copy of your dictionary .

newMy_dict = my_dict.copy()
if 'key' in newMy_dict :
    del newMy_dict['key']

This way , you can control exception.

Abhishek
  • 69
  • 1
  • 4
4

I prefer the immutable version

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}
CervEd
  • 1,682
  • 18
  • 18
4

Single filter on key

  • return "key" and remove it from my_dict if "key" exists in my_dict
  • return None if "key" doesn't exist in my_dict

this will change my_dict in place (mutable)

my_dict.pop('key', None)

Multiple filters on keys

generate a new dict (immutable)

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()
            )
    )
)
ZenG
  • 119
  • 3
3

You could also use filter with lambda:

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> dict(filter(lambda x: x[0] != 'a', d.items()))
{'b': 2, 'c': 3}
>>>
U12-Forward
  • 65,118
  • 12
  • 70
  • 89
1

Try this

if key in data:
   del data[key]
muTheTechie
  • 1,090
  • 12
  • 22