As mentioned an issue with dct.get(key, default) is that, if key exists but is mapped to a falsy value (e.g. None), you will get that value, not default.
If you want to return a default value even when key exists but is mapped to None, you can use this implementation:
class MyDict(dict): def myget(self, key, default=None): """Get value by key, return default if key is missing or is mapped to a falsy value.""" val = self.get(key, default) if val is None: val = default if isinstance(val, dict): val = MyDict(val) return val
Let's see an use case.
Suppose you get external data from a third-party that looks like this:
d1 = {"name":"Mark", "belongings":{"bycicles":2, "cars":5, "trucks":2}} d2 = {"name":"Peter"} d3 = {"name":"John", "belongings":None}
To get the number of cars that belongs to Mark, you would do:
d1.get("belongings").get("cars") # 5
and this would correctly return 5.
But if you use this to get the number of Peter's cars:
d2.get("belongings").get("cars") # throws AttributeError: 'NoneType' object has no attribute 'get'
you would get an Exception because d2 does not have a belongings key, so the first gest returns None.
To fix this, you would do:
d2.get("belongings", {}).get("cars", 0) # returns 0
This owuld correctly returns 0.
Now let's get the number of John's cars:
d3.get("belongings", {}).get("cars", 0) # throws AttributeError: 'NoneType' object has no attribute 'get'
This would throw an error because in d3 the key belongings is mapped to a None value, which is then returned.
Now let's use our implementation:
MyDict(d3).myget("belongings", {}).myget("cars", 0) # 0
.get(key)instead of[key]