Dictionaries are considered a keystone of Python and every programming language. Python’s Standard Library is especially helpful, providing ready-to-use mapping that can be very effective when used the correct way. So in this article, we will discuss what makes Python's Dictionaries special. Dict Comprehension The syntax of list comprehension has been adapted to dictionaries; a builds a by taking the pairs {key: value} from any dictComp dict instance iterable. dial_codes = [ (55, 'Brazil'), (86, 'China'), (91, 'India'), (62, 'Indonesia'), (81, 'Japan'), (7, 'Russia'), (1, 'United States'), ] country_dial = {country: code for code, country in dial_codes} print(country_dial) # {'Brazil': 55, 'China': 86, 'India': 91, 'Indonesia': 62, 'Japan': 81, 'Russia': 7, 'United States': 1} code_less_than_70 = {code: country.upper() for country, code in sorted(country_dial.items()) if code < 70} print(code_less_than_70) # {55: 'BRAZIL', 62: 'INDONESIA', 7: 'RUSSIA', 1: 'UNITED STATES'} Unpacking Mappings Unpacking dictionaries is similar to unpacking a list only you will be unpacking a pair of and it’s done with ** rather than the operator**.** {key: value} * There are a few key points to retain: We can apply the Operator to in a function call. ** more than one argument Duplicate keyword arguments are in so make sure your unpacked dictionary keys are unique. forbidden function calls, The Operator can be used inside a dict literal also multiple times. ** def dump(**kwargs): return kwargs print(dump(**{'x': 1}, y=2, **{'z': 3})) # {'x': 1, 'y': 2, 'z': 3} print(dump(**{'x': 1}, y=2, **{'z': 3, 'x': 6})) # TypeError: dump() got multiple values for keyword argument 'x' print({'a': 0, **{'x': 1}, 'y': 2, **{'z': 3, 'x': 4}} # Duplicate keys are allowed here and they get overwritten by the last occurence #{'a': 0, 'x': 4, 'y': 2, 'z': 3} Merging Dictionaries Dictionaries support the Set Union Operators: The Operator when merging. | creates a new mapping The Operator when merging. |= updates the first operand d1 = {'a': 1, 'b': 3} d2 = {'a': 2, 'b': 4, 'c': 6} print(d1 | d2) # overwriting the last occurence {'a': 2, 'b': 4, 'c': 6} d1 |= d2 print(d1) # {'a': 2, 'b': 4, 'c': 6} Automatic Handling of Missing Keys Imagine a scenario where a program tries to access a value in a dict by its key, only to not find it. There are two ways to handle this. Use a defaultdict A instance creates items with a default value on demand whenever a missing key is searched using the d[k] syntax. defaultdict from collections import defaultdict # Function to return a default values for keys that is not present def def_value(): return "This guest did not check in yet" # Defining the dict d = defaultdict(def_value) d["guest_1"] = "Adam" d["guest_2"] = "Eve" print(d["guest_1"]) # Adam print(d["guest_2"]) # Eve print(d["guest_3"]) # This guest did not check in yet Implement the ***Missing*** Method We can also implement the method in dict or any other mapping type. missing class GuestDict(dict): def __missing__(self, key): return 'This guest did not check in yet' x = {"guest_1": "Adam", "guest_2": "Eve"} guest_dict = GuestDict(x) # Try accessing missing key: print(guest_dict['guest_3']) # This guest did not check in yet Dictionary Views The instance methods , , and return instances of classes called , , and that are read-only but are of the real . dict .keys() .values() .items() dict_keys dict_values dict_items dynamic proxies dict If the source is , you can through an existing view. dict updated immediately see the changes d = {'a': 5, 'b': 2, 'c': 0, 'd': 7} v = d.values() print('values before before updating : ', v) # values before before updating : dict_values([5, 2, 0, 7]) d['e'] = 5 print('Dictionary after adding new value', d) # Dictionary after adding new value {'a': 5, 'b': 2, 'c': 0, 'd': 7, 'e': 5} # dynamic view object is updated automatically print('value of the updated dictionary: ', v) # value of the updated dictionary: dict_values([5, 2, 0, 7, 5]) Different Flavors of Dict There are different variations of that are ready to use, and we can leverage them to gain time. dict collections.OrderedDict These are regular dictionaries but have some extra capabilities relating to you can find more about them . ordering operations; here collections.ChainMap A instance holds a list of that can be . ChainMap mappings searched as one The lookup is performed on each input mapping in the order it appears in the constructor call and succeeds as soon as the key is found in one of those mappings. baseline = {'music': 'bach', 'art': 'rembrandt'} adjustments = {'art': 'van gogh', 'opera': 'carmen'} print(list(ChainMap(adjustments, baseline))) # ['music', 'art', 'opera'] collections.Counter A mapping that holds an count for each key. Updating an existing key adds to its count. integer ct = collections.Counter('abracadabra') print(ct) # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) ct.update('aaaaazzz') print(ct) # Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) print(ct.most_common(3)) # [('a', 10), ('z', 3), ('b', 2)] shelve.Shelf The shelve module (naming is inspired by the fact that Pickle jars are stored on shelves) in the standard library provides persistent storage for a mapping of string keys to Python objects serialized in the Pickle binary format. UserDict The UserDict has some methods that are ready to use rather than having to implement or reinvent the wheel by extending the dict class; find more about it . here MappingProxyType This is a wrapper class that, given a mapping type, returns a instance that is but mappingproxy read-only mirrors the changes from the original mapping. from types import MappingProxyType d = {1: 'A'} d_proxy = MappingProxyType(d) print(d_proxy) # mappingproxy({1: 'A'}) print(d_proxy[1]) # "A" d[2] = 'B' print(d_proxy) # mappingproxy({1: 'A', 2: 'B'}) print(d_proxy[2]) # "B" The Mechanics of a Python Dictionary Python’s dict implementation is very efficient as it’s based on a hash table, but there are a few things to keep in mind. Keys must be hashable objects. They must implement proper ** and methods. **hash eq Item access by key is very fast. A dict may have millions of keys, but Python can locate a key directly by computing the hash code of the key and deriving an index offset into the hash table. It's better to avoid creating dict instance attributes outside of the method since it saves memory. init inevitably have a . Dicts significant memory overhead Further Reading The full article is on my . Blog . The third Chapter of the book Fluent Python The Python Standard Library Documentation, “ ”, includes examples and practical recipes with several mapping types. collections Container datatypes Python's Standard Library Documentation on . Shelves The first chapter of the book Python Cookbook, 3rd ed