Reputation: 3949
Suppose I want to create a dict
(or dict
-like object) that returns a default value if I attempt to access a key that's not in the dict
.
I can do this either by using a defaultdict
:
from collections import defaultdict
foo = defaultdict(lambda: "bar")
print(foo["hello"]) # "bar"
or by using a regular dict
and always using dict.get(key, default)
to retrieve values:
foo = dict()
print(foo.get("hello", "bar")) # "bar"
print(foo["hello"]) # KeyError (as expected)
Other than the obvious ergonomic overhead of having to remember to use .get()
with a default value instead of the expected bracket syntax, what's the difference between these 2 approaches?
Upvotes: 5
Views: 6047
Reputation: 93
Asides from the ergonomics of having .get
everwhere, one important difference is if you lookup a missing key in defaultdict
it will insert a new element into itself rather than just returning the default. The most important implications of this are:
defaultdict
defaultdict
, with .get
the default is lost unless stored explictyfrom collections import defaultdict
default_foo = defaultdict(list)
dict_foo = dict()
for i in range(1024):
default_foo[i]
dict_foo.get(i, [])
print(len(default_foo.items())) # 1024
print(len(dict_foo.items())) # 0
# Defaults in defaultdict's can be mutated where as with .get mutations are lost
default_foo[1025].append("123")
dict_foo.get(1025, []).append("123")
print(default_foo[1025]) # ["123"]
print(dict_foo.get(1025, [])) # []
Upvotes: 5
Reputation: 77
The difference here really comes down to how you want your program to handle a KeyError.
foo = dict()
def do_stuff_with_foo():
print(foo["hello"])
# Do something here
if __name__ == "__main__":
try:
foo["hello"] # The key exists and has a value
except KeyError:
# The first code snippet does this
foo["hello"] = "bar"
do_stuff_with_foo()
# The second code snippet does this
exit(-1)
It's a matter of do we want to stop the program entirely? Do we want the user to fill in a value for foo["hello"] or do we want to use a default value?
The first approach is a more compact way to do foo.get("hello", "bar")
But the kicker is the matter of is this what we really want to happen?
Upvotes: 0