Federico Ponzi Federico Ponzi - 4 months ago 6
Python Question

strange dict.get behaviour

Seems like the fallback is called even if the key is present inside the dictionary. Is this an intended behaviour? How can workaround it?

>>> i = [1,2,3,4]
>>> c = {}
>>> c[0]= 0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
0
>>> c.get(0, i.pop())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop from empty list

Answer

When doing c.get(0, i.pop()), the i.pop() part gets evaluated before the result it returns is passed to the c.get(...). That's the reason that the error appears if a list i is empty due to the previous .pop() calls on it.

To get around this, you should either check if the list is not empty before trying to pop an element from it, or just try it an catch a possible exception:

if not i:
    # do not call do i.pop(), handle the case in some way

default_val = i.pop()

or

try:
  c.get(0, i.pop())
except IndexError:
    # gracefully handle the case in some way, e.g. by exiting

default_val = i.pop()

The first approach is called LBYL ("look before you leap"), while the second is referred to as EAFP ("easier to ask for forgiveness than permission"). The latter is usually preferred in Python and considered more Pythonic, because the code does not get cluttered with a lot of safeguarding checks, although the LBYL approach has its merits, too, and can be just as readable (use-case dependent).

Comments