Mapping Types ============= .. toctree:: :maxdepth: 1 Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` Definition ---------- A mapping is a container type that stores a collection of zero or more key-value pairs. The keys must be :term:`hashable`, but the values can be any arbitrary Python object. Values need not all be the same type, and values can nest other container types. Values in a mapping are indexed by key using the item access operator ``[]``. .. _section_heading-Dict: Dict ---- **MUTABILITY:** Mutable The :py:class:`dict` (dictionary) is currently the only intrinsic mapping type defined by the Python data model. Items in a dictionary are stored **unordered**. Since dictionaries are mutable, you can modify the keys and values after creation without forcing Python to create a new object. Dictionaries can be constructed in a variety of ways: * Using curly brackets ``{}``. For example: To create a dictionary with 0 items: >>> foo = {} >>> foo {} To create a dictionary from key-value pairs using ``:`` as the separator: >>> foo = {'a': 1, 'b': 2, 'c': 3} >>> foo {'a': 1, 'b': 2, 'c': 3} * Using an expression in curly brackets ``{}`` to create a dict comprehension. For example: >>> foo = {'jim jones': ('Eng', 100), ... 'bim bartman': ('Eng', 341), ... 'jake king': ('Eng', 99), ... 'kyle zapp': ('Mkt', 921), ... 'moon yee': ('Mkt', 472), ... 'sun tzu': ('Mkt', 8294), ... 'tick tock': ('Fin', 46)} >>> bar = {key.title(): val[0] for key, val in foo.items()} >>> bar {'Bim Bartman': 'Eng', 'Jake King': 'Eng', 'Jim Jones': 'Eng', 'Kyle Zapp': 'Mkt', 'Moon Yee': 'Mkt', 'Sun Tzu': 'Mkt', 'Tick Tock': 'Fin'} >>> baz = {key.title(): val[1] for key, val in foo.items() if val[0] == "Mkt"} >>> baz {'Kyle Zapp': 921, 'Moon Yee': 472, 'Sun Tzu': 8294} * Using the :py:class:`dict` constructor, which allows you to do several things: With no arguments, it creates and empty dictionary: >>> foo = dict() >>> foo {} With arguments passed as keywords, it uses the first as the key and the second as the value: >>> foo = dict(a=1, b=2, c=3) >>> foo {'a': 1, 'b': 2, 'c': 3} .. note:: You can only use keyword arguments to the :py:class:`dict` constructor if the keys are considered valid Python identifiers. For example, the key, "jim bob" is not a valid Python identifier and it's use would result in a :py:exc:`SyntaxError` being thrown. When passed a sequence, where each item in the sequence is itself a sequence of 2 objects, it builds the dictionary using the first object as the key and the second as the value: >>> foo = dict([('a', 1), ('b', 2), ('c', 3)) >>> foo {'a': 1, 'b': 2, 'c': 3} When passed a dictionary, this is one way of :term:`shallow-copy` ing the dictionary: >>> foo = {'a': 1, 'b': 2, 'c': 3} >>> bar = dict(foo) >>> bar {'a': 1, 'b': 2, 'c': 3} Individual items in a mapping can be indexed using the item access operator ``[]``, which takes a key, as in, ``[key]``. If key doesn't exist, you will get a :py:class:`KeyError`. .. tip:: To avoid getting a :py:class:`KeyError` for keys that don't exist, you can use the :py:class:`collections.defaultdict` type, which has all the same methods as the :py:class:`dict` class, but, allows you to specify a default value to use for keys that don't exist. If an attempt is made to access the dictionary using a key that doesn't exist, the key is created and the value set to the default value. For example: >>> import collections >>> foo = collections.defaultdict(int) >>> foo['a'] >>> foo['b'] >>> foo defaultdict(int, {'a': 0, 'b': 0}) Due to the fact that mappings store unordered items, it is not possible to slice or stride them. Dictionaries compare equal if the have the same key:value pairs. For example: >>> foo = {'a': 1, 'b': 2, 'c': 3} >>> bar = {'b': 2, 'c': 3, 'a': 1} >>> baz = {'d': 4, 'e': 5, 'f': 6} >>> bif = {'a': 1, 'b': 2} >>> foo == bar True >>> foo == baz False >>> foo == bif False Dictionaries don't support comparing using ``<``, ``<=``, ``>`` and ``>=``. .. _section_heading-Dict_Specific_Methods: Dict Specific Methods ^^^^^^^^^^^^^^^^^^^^^ The dict type supports the operations shown in :numref:`table-Dict_Specific_Operations`. .. _table-Dict_Specific_Operations: .. table:: Table of Dict Specific Operations +------------------------------+--------------------------------------------------------------------------+ | Operation | Description | +==============================+==========================================================================+ | len(d) | Return the number of items in the dictionary ``d``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> len(foo) | | | 5 | +------------------------------+--------------------------------------------------------------------------+ | d[key] | Return the item of ``d`` with key ``key``. | | | | | | Raises :py:exc:`KeyError` if ``key`` in not in map. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo['a'] | | | 1 | +------------------------------+--------------------------------------------------------------------------+ | d[key] = val | Sets ``key`` in ``d`` to ``val``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo['a'] = 99 | | | >>> foo | | | {'a': 99, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | +------------------------------+--------------------------------------------------------------------------+ | del d[key] | Remove the item of ``d`` with key ``key``. | | | | | | Raises :py:exc:`KeyError` if ``key`` in not in map. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> del foo['a'] | | | >>> foo | | | {'b': 2, 'c': 3, 'd': 4, 'e': 5} | +------------------------------+--------------------------------------------------------------------------+ | key in d | Membership testing. Returns :py:obj:`True` if ``key`` is in ``d``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> 'a' in foo | | | True | +------------------------------+--------------------------------------------------------------------------+ | key not in d | Membership testing. Returns :py:obj:`True` if ``key`` is not in ``d``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> 'z' not in foo | | | True | +------------------------------+--------------------------------------------------------------------------+ | iter(d) | Returns an iterator over the **keys** of the dictionary. | | | | | | Allows dict objects to be iterated over using ``for`` loops. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> for key in foo: | | | ... print("{}:{}".format(key, foo[key])) | | | b:2 | | | c:3 | | | d:4 | | | e:5 | | | a:1 | +------------------------------+--------------------------------------------------------------------------+ | d.items() | Return a new view of the dictionary’s items (its (key, value) pairs). | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.items() | | | dict_items([('b', 2), ('c', 3), ('d', 4), ('e', 5), ('a', 1)]) | | | >>> list(foo.items()) | | | [('b', 2), ('c', 3), ('d', 4), ('e', 5), ('a', 1)] | | | >>> for item in foo.items(): | | | ... print(item) | | | ('b', 2) | | | ('c', 3) | | | ('d', 4) | | | ('e', 5) | | | ('a', 1) | +------------------------------+--------------------------------------------------------------------------+ | d.keys() | Returns a view of the dictionary's keys. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.keys() | | | dict_keys(['b', 'c', 'd', 'e', 'a']) | | | >>> list(foo.keys()) | | | ['b', 'c', 'd', 'e', 'a'] | | | >>> for key in foo.keys(): | | | ... print(key) | | | b | | | c | | | d | | | e | | | a | +------------------------------+--------------------------------------------------------------------------+ | d.values() | Return a new view of the dictionary’s values. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.values() | | | dict_values([2, 3, 4, 5, 1]) | | | >>> list(foo.values()) | | | [2, 3, 4, 5, 1] | | | >>> for val in foo.values(): | | | ... print(val) | | | 2 | | | 3 | | | 4 | | | 5 | | | 1 | +------------------------------+--------------------------------------------------------------------------+ | d.clear() | Removes all items from the dictionary ``d``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.clear() | | | >>> foo | | | {} | +------------------------------+--------------------------------------------------------------------------+ | d1 = d0.copy() | Return a shallow copy of dictionary ``d0``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> bar = foo.copy() | | | >>> bar | | | {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | +------------------------------+--------------------------------------------------------------------------+ | dict.fromkeys(seq[, val]) | Create new dictionary with keys from ``seq`` and values set to ``val``. | | | | | | >>> foo = dict.fromkeys(['a', 'b', 'c'], 1) | | | >>> foo | | | {'a': 1, 'b': 1, 'c': 1} | +------------------------------+--------------------------------------------------------------------------+ | d.get(key[, default]) | Return the value for ``key`` if ``key`` is in the dict, else default. | | | | | | Never raises :py:exc:`KeyError` as default ``default`` is :py:obj:`None`.| | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.get('f', 99) | | | 99 | +------------------------------+--------------------------------------------------------------------------+ | d.pop(key[, default]) | If ``key`` is in the dictionary, remove it and return its value. | | | | | | If not, return ``default``. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.pop('c') | | | 3 | | | >>> foo | | | {'a': 1, 'b': 2, 'd': 4, 'e': 5} | +------------------------------+--------------------------------------------------------------------------+ | d.popitem() | Remove and return an arbitrary (key, value) pair from the dictionary. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.popitem() | | | ('b', 2) | | | >>> foo | | | {'a': 1, 'c': 3, 'd': 4, 'e': 5} | +------------------------------+--------------------------------------------------------------------------+ | d.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 :py:obj:`None`. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.setdefault('f', 99) | | | 99 | | | >>> foo | | | {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 99} | +------------------------------+--------------------------------------------------------------------------+ | d.update([x]) | Update the dictionary ``d`` with the key/value pairs from ``x``. | | | | | | Existing keys are overwritten. | | | | | | ``x`` can be a dict, a sequence of key/val pairs, or keyword arguments. | | | | | | >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} | | | >>> foo.update({'f': 6}) | | | >>> foo.update([('g', 7), ('h', 8)]) | | | >>> foo.update(i=9) | | | >>> foo | | | {'a': 1, | | | 'b': 2, | | | 'c': 3, | | | 'd': 4, | | | 'e': 5, | | | 'f': 6, | | | 'g': 7, | | | 'h': 8, | | | 'i': 9} | +------------------------------+--------------------------------------------------------------------------+ The methods, :py:meth:`~dict.items`, :py:meth:`~dict.keys` and :py:meth:`~dict.values` return dictionary view objects. These are read-only objects that can be iterated over and who's content changes when the underlying dictionary changes. The advantage to dictionary view objects is they allow :py:class:`set` type operations on them if their contents are unique. .. note:: Dictionary *keys* are always unique. Dictionary *values* may or may not be unique. Dictionary *items* are unique only if keys and values are all unique. For example: * Union (return a new set with elements from the set and all others) >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} >>> bar = {'a': 99, 'f': 6, 'g': 7} >>> bif = {'a': 200, 'c': 444, 'h': 555} >>> foo.keys() | bar.keys() | bif.keys() {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'} * Intersection (return a new set with elements common to the set and all others) >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} >>> bar = {'a': 99, 'f': 6, 'g': 7} >>> bif = {'a': 200, 'c': 444, 'h': 555} >>> foo.keys() & bar.keys() & bif.keys() {'a'} * Difference (return a new set with elements in the set that are not in the others) >>> foo = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5} >>> bar = {'a': 99, 'f': 6, 'g': 7} >>> bif = {'a': 200, 'c': 444, 'h': 555} >>> foo.keys() - bar.keys() - bif.keys() {'b', 'd', 'e'} .. admonition:: Try it! :class: TryIt Try the following: * Create an empty dict. * Add the following key:value pairs to the empty dict you just created: * 'girls' : 3 * 'boys' : 5 * 'dogs' : 1 * Copy the following dictionary: .. code-block:: python {'John' : ('Hamilton', 20), 'Sam' : ('Hamilton', 32), 'Cass' : ('Toronto', 52), 'Nathan': ('Toronto', 36), 'Alison': ('Hamilton', 27), 'Erin' : ('Toronto', 43), 'Kevin' : ('Burlington', 62), 'Julia' : ('Toronto', 58) } * Get the keys from the copy of the dictionary above. * Remove "Nathan" from the copy of the dictionary above. * Merge the first dictionary above with the copy of the dictionary above.