简体   繁体   中英

Python defaultdict(default) vs dict.get(key, default)

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?

Asides from the ergonomics of having .get everyone, 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:

  • Later iterations will retrieve all keys looked up in a defaultdict
  • As more ends up stored in the dictionary, more memory is typically used
  • Mutation of the default will store that mutation in a defaultdict , with .get the default is lost unless stored explicty
from 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, [])) # []

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM