kederrac
kederrac

Reputation: 17322

dict.pop versus dict.get on the default return value

I'm trying to figure out what is the reason for having None as the default value for dict.get but no default value (without specifying the default value) for dict.pop

{}.get('my_key')
# output: None
{}.pop('my_key')
# output: KeyError: 'my_key'

I was thinking that the reason for not having implicit default value for dict.pop is because you may have keys with value None so, in order to not get confused if your key is in the dictionary or not, an implicit default value for dict.pop doesn't make so much sense. But then again this explanation should be valid also for dict.get and isn't:

{'my_key': None}.get('my_key')
# output: None
# but doesn't tell you if the key is truly in the dictionary or not

Upvotes: 9

Views: 4067

Answers (6)

mxzlamas
mxzlamas

Reputation: 21

This is what i believe:

pop() main purpose: value+deletion get() main purpose: value

if the 'value' part fails, your program can deal with it, None might even be fine to continue with. Maybe you just wanted to test if a key was there. Using get() is actually named as a solution to check-if-value-is-present-in-dict questions.

if 'deletion' fails you usually didn't test-delete, but actually wanted to delete and made some e.g. indexing mistake. So if that did not work, you should be informed.

so you might say "this behaviour is the result of the definition, not the explanation", yes and the explanation i think, is, that the same behaviour was present in other programming languages (C) before and it made sense to implement it into python. It might lay even deeper though.

FredrikHedman's response:

In short a good example of the "principle of least surprise" and the Zen of Python (import this) :)

this also makes sense for me

Upvotes: 0

FredrikHedman
FredrikHedman

Reputation: 1253

My take on this is to allow a dict to be used with different contexts.

With dict.get(key) we always get a value even if the key is not present in dict. The default value can be provided. No exception is raised. The dict is not changed.

With dict.pop(key) we get a value only when the key is present in dict, otherwise an exception is raised. We may avoid the exception by providing a default value. The dict is changed.

To test for the presence of key we use key in dict.

For dict.pop, this gives a similar interface to what list.pop, set.pop and deque.pop provides.

In short a good example of the "principle of least surprise" and the Zen of Python (import this) :)

Upvotes: 2

Alexander Brockmeier
Alexander Brockmeier

Reputation: 98

Here an example to show you what is basically going on under the hood, if the key exists, also showing the difference between both:

In [3]: foo = {'my_key': 'value', 'other_key': 'other_val'}                                  

In [4]: foo.get('my_key')                                                                    
Out[4]: 'value'

In [5]: bar = foo.pop('other_key')                                                           

In [6]: bar                                                                                  
Out[6]: 'other_val'

In [7]: foo                                                                                  
Out[7]: {'my_key': 'value'}

In [8]:  

Upvotes: 0

Keven Li
Keven Li

Reputation: 634

The method which read the exact value for key is

{}['my_key']

The dict.get(key[, default]) is the try get value, if not return "default" version.

help(dict.get)

get(...)
    D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.

Upvotes: 3

r.ook
r.ook

Reputation: 13888

If your primary concern is if a key exists within the dictionary, it should be done via 'my_key' in my_dict. .get and .pop as you can imagine serves slightly different purposes. .get is strictly retrieval, and .pop is retrieval and removal. You will want to use the respective method that best suit your use case, and employ a default value if you don't need to handle a KeyError.

As for the reason of why .pop doesn't use a default value by default, it is because that the operation expects to also remove a key from the dictionary. If the operation was completed successfully without raising an error, one might erroneously expect the key to be removed from the dictionary as well.

For .get, the method exists specifically as a alternative to provide a default value over the __getitem__ method, which you usually see the syntax as my_dict['my_key']. The latter of which, will raise a KeyError if the key doesn't exist.

Upvotes: 7

chepner
chepner

Reputation: 531993

get exists, in some sense, in two varieties: one raises a KeyError, the other doesn't.

>>> {}['my_key']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'my_key'
>>> {}.get('my_key')
>>>

pop, on the other hand, isn't an error-free version of another operation that raises a KeyError, so it's used in both situations: raising a KeyError by default, but returning a default value if requested.

>>> {}.pop('my_key')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'my_key'
>>> {}.pop('my_key', 3)
3

Upvotes: 5

Related Questions