Yesterday I spent way more time than neccessary debugging a piece of python code. It has something to do with how the python dictionary’s get method works with default arguments. TLDR: it is ok when default is a simple value, not recommended if default is a function call.

Here is what the problematic code looks like:

def get_option(option_name):
option = # some logic
return option

x = d.get("option_1", default=get_option("option_1"))


The problem here is that the default argument is a pointer to the return value of a function call, thus the function will be evaluated before the body of the get method. So no matter whether the key exists or not, the function will always be evaluated. It can break if:

1. the function is not defined.
2. the function call raises an Error or Exception.

The fix is change it to:

x = d.get("option_1", default=None) or get_option("option_1")


So that the function call will be used as a last resort when key is not in the dictionary.

But one drawback is that, if the value is logically False, like a int value 0, it will still fallback to the function call.

So a better rewrite is:

x = d["option_1"] if "option_1" in d else get_option("option_1")


This is slightly different to collections.defaultdict. In which, the fallback default_factory callable is only called after the key check. But ofcourse, default_factory does not accept any argument, thus does not suit the usecase here.