# Containers¶

At one point you may want to keep objects like strings or numbers in another object to show that they are strongly related. These objects that contain other objects are called container. Python offers a fair amount of useful containers out of the box, some of which are introduced in the following.

## Lists¶

If you need a flexible container that can take in about anything (even itself) and you need to keep an order to the contained objects you should use a list. An empty list is generated by either

>>> list()
[]


or

>>> []
[]


Or you generate a non-empty list

>>> list([1, 2, 3])
[1, 2, 3]


or

>>> [1, 2, 3]
[1, 2, 3]


Accessing values for the list is done like this:

>>> x = [1, 2, 3]
>>> print(x[1])
2


Note

As you can see in the example above specifying x[1] did not give you the first element of the list, but the second. This is due to Python starting indexing at 0!

With this you can also change values in a list

>>> x = [1, 2, 3]
>>> x[1] = 4
>>> print(x)
[1, 4, 3]


Negative indices can be used to retrieve element from the end:

>>> x = [1, 2, 3, 4, 5]
>>> print(x[-1])
5
>>> print(x[-2])
4


You can also create slices of the list using the following notation:

list[start:end:step]


Its usage is best made clear by some examples:

>>> x = ['zero', 'one', 'two', 'three', 'four']
>>> print(x[2:])
['two', 'three', 'four']
>>> print(x[:3])
['zero', 'one', 'two']
>>> print(x[1:3])
['one', 'two']
>>> print(x[::2])
['zero', 'two', 'four']
>>> print(x[::-1])
['four', 'three', 'two', 'one', 'zero']
>>> print(x[-2:])
['three', 'four']


You can also append values to a list

>>> x = [1, 2, 3]
>>> print(x)
[1, 2, 3]
>>> x.append(4)
>>> print(x)
[1, 2, 3, 4]


or insert values at specified positions

>>> x = [1, 2, 3]
>>> print(x)
[1, 2, 3]
>>> x.insert(0, -1)
>>> print(x)
[-1, 1, 2, 3]
>>> x.insert(1, 0)
>>> print(x)
[-1, 0, 1, 2, 3]


A list can hold anything, even other lists

>>> [1, 'two', ['three', 4]]
[1, 'two', ['three', 4]]


## Tuples¶

If you are sure that you do not want to modify the data container after its generation and want to keep everything in the order you specified the tuple container is the container of choice. They may be initialized by

>>> tuple([1, 2, 3])
(1, 2, 3)
>>> (1, 2, 3)
(1, 2, 3)


Accessing single elements is done like in lists:

>>> x = (1, 2, 3)
>>> print(x[1])
2


And when you try to modify them an error is raised:

>>> x = (1, 2, 3)
>>> x[1] = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment


## Sets¶

If you do not want duplicates in your container and you do not care about their order you should use a set. They are initialized via

>>> set()  # This one is empty
set()
>>> set([1, 2, 2, 3, 3, 'three'])
{1, 2, 3, 'three'}
>>> {1, 2, 2, 3, 3, 'three'}
{1, 'three', 2, 3}


and elements can be added like this:

>>> x = {1, 2, 3}
>>> print(x)
{1, 2, 3}
>>> print(x)
{1, 2, 'four', 3}


Sets furthermore support a lot of the operators you are familiar with from the set in mathematics. For further information see the Python documentation.

## Dictionaries¶

If you do not want to keep the order of things but would rather like to use keys to access the objects in the container the dict has got you covered. Dicts are initialized via

>>> dict()
{}
>>> {}
{}
>>> x = {'One': 1, 'two': 2, 'THREE': ['A', 'list', 'of', 'strings']}
{'THREE': ['A', 'list', 'of', 'strings'], 'One': 1, 'two': 2}


and their values may be accessed like this:

>>> x = {'One': 1, 'two': 2, 'THREE': ['A', 'list', 'of', 'strings']}
>>> x['One']
1
>>> x['THREE']
['A', 'list', 'of', 'strings']


As you can see there are no restrictions regarding the type of the value that each key is pointing to. Keys on the other hand have to be hashable. In practice the keys are usually ints or strings. If you want to retrieve something that does not exist an error is raised:

>>> x = {'One': 1, 'two': 2, 'THREE': ['A', 'list', 'of', 'strings']}
>>> x['four']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'four'


A way of providing a fallback in case a key does not exist in the dictionary is the dict.get() method:

>>> x = {'One': 1, 'two': 2, 'THREE': ['A', 'list', 'of', 'strings']}
>>> x.get('two', 'fallback')
2
>>> x.get('four', 'fallback')
'fallback'


## Common operations¶

### Length¶

Sometimes you are interested in the amount of objects that a container holds. This information can be accessed using the len() function:

>>> x = [1, 2, 3]
>>> len(x)
3
>>> x = (1, 2)
>>> len(x)
2
>>> x = set([1, 2, 2, 3, 3, 'three'])
>>> len(x)
4
>>> x = {'One': 1, 'two': 2, 'THREE': ['A', 'list', 'of', 'strings']}
>>> len(x)
3


### Membership check¶

>>> x = [1, 2, 3]
>>> 2 in x
True


Note

While the behavior is clear for lists, tuples and sets, the in checks for the keys of a dictionary.

>>> x = {
...    'one': 'two',
...    3: 4
... }
>>> 'one' in x
True
>>> 'two' in x
False
>>> 3 not in x
False
>>> 4 not in x
True


Due to the nature of the implementation member checks are especially fast in sets and dictionaries

## Summary¶

• use lists if the order is important and you may need to modify the container.
• use tuples if the order is important and the container is fixed.
• use sets if order is not important and you want to ensure uniqueness inside the container.
• use dictionaries if you want to store key-value pairs.