========== Containers ========== Sequence: ``list`` and ``tuple`` ================================ ``[]`` or ``list()`` constructs a list for you: .. doctest:: basic_container_seq >>> la = [] >>> lb = list() >>> print(la, lb) ([], []) Some built-ins return a list: .. doctest:: basic_container_seq >>> a = range(10) >>> print(type(a), a) (, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) A ``tuple`` can also hold anything, but cannot be changed once constructed. It can be created with ``()`` or ``tuple()``: .. doctest:: basic_container_seq >>> ta = (1) >>> print(type(ta), ta) (, 1) >>> ta = (1,) >>> print(type(ta), ta) (, (1,)) >>> ta[0] = 2 Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment \end{lstlisting} Slicing ======= List Comprehension ================== List comprehension is a very useful technique to construct a list from another iterable: .. doctest:: basic_container_seq >>> values = [10.0, 20.0, 30.0, 15.0] >>> print([it/10 for it in values]) [1.0, 2.0, 3.0, 1.5] List comprehension can even be nested: .. doctest:: basic_container_seq >>> values = [[10.0, 1.0], [20.0, 2.0], [30.0, 3.0], [15.0, 1.5]] >>> print([jt for it in values for jt in it]) [10.0, 1.0, 20.0, 2.0, 30.0, 3.0, 15.0, 1.5] Iterator ======== Use ``reversed()`` and ``sorted()`` as examples. Simple sort: .. doctest:: basic_container_seq >>> a = [87, 82, 38, 56, 84] >>> b = sorted(a) # b is a new list. >>> print(b) [38, 56, 82, 84, 87] >>> a.sort() # this method does in-place sort. >>> print(a) [38, 56, 82, 84, 87] Not-so-simple sort: .. doctest:: basic_container_seq >>> a = [('a', 0), ('b', 2), ('c', 1)] >>> print(sorted(a)) # sorted with the first value. [('a', 0), ('b', 2), ('c', 1)] >>> print(sorted(a, key=lambda k: k[1])) # use the second. [('a', 0), ('c', 1), ('b', 2)] Built-in calculation functions for iterables: .. doctest:: basic_container_seq >>> values = [10.0, 20.0, 30.0, 15.0] >>> min(values), max(it for it in values) (10.0, 30.0) >>> sum(values) 75.0 >>> sum(values)/len(values) 18.75 Set === A ``set`` holds any hashable element, and its elements are distinct: .. doctest:: basic_container_set >>> sa = {1, 2, 3} >>> print(type(sa), sa) (, set([1, 2, 3])) >>> print({1, 2, 2, 3}) # no duplication is possible. set([1, 2, 3]) >>> len({1, 2, 2, 3}) 3 It's unordered: .. doctest:: basic_container_set >>> [it for it in {3, 2, 1}] [1, 2, 3] >>> [it for it in {3, 'q', 1}] ['q', 1, 3] >>> 'q' < 1 False Add elements after construction of the set: .. doctest:: basic_container_set >>> sa = {1, 2, 3} >>> sa.add(1) >>> sa set([1, 2, 3]) >>> sa.add(10) >>> sa set([1, 2, 3, 10]) Remove elements: .. doctest:: basic_container_set >>> sa = {1, 2, 3, 10} >>> sa.remove(5) # err with non-existing element Traceback (most recent call last): File "", line 1, in KeyError: 5 >>> sa.discard(2) # really discard an element >>> sa set([1, 10, 3]) Subset or superset: .. doctest:: basic_container_set >>> {1, 2, 3} < {2, 3, 4, 5} # not a subset False >>> {2, 3} < {2, 3, 4, 5} # subset True >>> {2, 3, 4, 5} > {2, 3} # superset True Union and intersection: .. doctest:: basic_container_set >>> {1, 2, 3} | {2, 3, 4, 5} # union set([1, 2, 3, 4, 5]) >>> {1, 2, 3} & {2, 3, 4, 5} # intersection set([2, 3]) >>> {1, 2, 3} - {2, 3, 4, 5} # difference set([1]) A ``set`` can be used with a sequence to quickly calculate unique elements: .. doctest:: basic_container_set >>> data = [1, 2.0, 0, 'b', 1, 2.0, 3.2] >>> sorted(set(data)) [0, 1, 2.0, 3.2, 'b'] But there's a problem: It doesn't support unhashable objects: .. doctest:: basic_container_set >>> data = [dict(a=200), 1, 2.0, 0, 'b', 1, 2.0, 3.2] >>> set(data) Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'dict' Read the Python Cookbook for a solution :-) Dictionary ========== A ``dict`` stores any number of key-value pairs. It is the most used Python container since it's everywhere for Python namespace. .. doctest:: basic_container_dict >>> {'a': 10, 'b': 20} == dict(a=10, b=20) True >>> da = {1: 10, 2: 20} # any hashable can be a key >>> da[1] + da[2] 30 >>> class SomeClass(object): ... pass ... >>> print(type(SomeClass().__dict__)) To test whether something is in a dictionary or not: .. doctest:: basic_container_dict >>> da = {1: 10, 2: 20} >>> 3 in da False Access a key-value pair: .. doctest:: basic_container_dict >>> da[3] # it fails for 3 is not in the dictionary Traceback (most recent call last): File "", line 1, in KeyError: 3 >>> print(da[3] if 3 in da else 30) # works but wordy 30 >>> da.get(3, 30) # it's the way to go 30 >>> da # indeed we don't have 3 as a key {1: 10, 2: 20} >>> da.setdefault(3, 30) # how about this? 30 >>> da # we added 3 into the dictionary! {1: 10, 2: 20, 3: 30} Iterating a ``dict`` automatically gives you its keys: .. doctest:: basic_container_dict >>> da = {1: 10, 2: 20} >>> ','.join('%s'%key for key in da) '1,2' >>> ','.join('%d'%da[key] for key in da) '10,20' ``items()`` and ``iteritems()`` give you both key and value at once: .. doctest:: basic_container_dict >>> da.items() # returns a list [(1, 10), (2, 20)] >>> type(da.iteritems()) # returns an iterator >>> ','.join('%s:%s'%(key, value) for key, value in da.iteritems()) '1:10,2:20' A dictionary view changes with the dictionary: .. doctest:: basic_container_dict >>> da = {1: 10, 2: 20} >>> daiit = da.iteritems() # an iterator >>> type(daiit) >>> davit = da.viewitems() # a view object >>> davit dict_items([(1, 10), (2, 20)]) >>> da[3] = 30 # change the dictionary >>> ','.join('%s:%s'%(key, value) for key, value in daiit) Traceback (most recent call last): File "", line 1, in File "", line 1, in RuntimeError: dictionary changed size during iteration >>> ','.join('%s:%s'%(key, value) for key, value in davit) '1:10,2:20,3:30' Dictionary for Switch-Case ++++++++++++++++++++++++++ Make Your Own Data Structures: Collection ABCs ============================================== .. vim: set spell ft=rst ff=unix fenc=utf8 ai et sw=4 ts=4 tw=79