Jan-Philipp Litza

Subtle 15. June 2017

I just stumbled across this great coding error of mine and thought I could share it while waiting for the corrected program to finish its run.

My previous code read like this:

if key not in d:
    d[key] = get_value()
return d[key]

I thought “Hey, dict.setdefault() would come in handy here”, as its documentation says

setdefault(key[, default])

If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.

So I replaced the code by

return d.setdefault(key, get_value())

Looks alright, right? Wrong, as I was greeted by an infinite recusion I couldn’t explain at first. But the difference is obvious: In the previous form, get_value() only gets executed if it is not known, while in the second form, get_value() is always executed, which caused the recusion.

So while the documentation is totally correct in reading like the two forms would be equivalent, general programming theory or whatever you want to call it makes the difference. Subtle!