Lists, Tuples and Dictionaries
There’s two more basic types in Python that you should know before going forward. Lists and dictionaries are very common in Python and are structures you can use to organise your data.
Lists
Lists are just what they sound like: they’re an ordered collection of things. Like a shopping list, or a top ten list, it’s a convenient way for you to write code that processes things in a deliberate order.
For our example, we’re going to make a simple travel diary. Here’s a list of countries Alice wants to visit one day, sorted in order of preference:
- Mexico
- Portugal
- Kenya
- Nepal
- New Zealand
If we were to represent this as a Python list, we’d use the [
and ]
characters:
places_to_visit = ["Mexico", "Portugal", "Kenya", "Nepal", "New Zealand"]
Indexes
The primary trait of lists is that they’re sorted. This means that if you ask
a list for its first element, it will always be the same value unless you
modify that list. In other words, given the above, you should always be able
to say “what is the 3rd value in my list” and always get Kenya
.
The tricky/annoying part of indexing however is that it starts at 0, not 1,
which is where most people would expect things to start. This means that the
first element of a list is referred to with a 0
, the second element is
referred to with a 1
, and so on. Perhaps an example would be helpful:
>>> print(places_to_visit[0])
'Mexico'
>>> print(places_to_visit[2])
'Kenya'
Positive numbers aren’t the only thing you can use for indexes though. Negative
numbers invert the index, so you can get the last element of a list by using
-1
, or the third-to-last by using -3
:
>>> print(places_to_visit[-1])
'New Zealand'
>>> print(places_to_visit[-3])
'Kenya'
Try it yourself now: Try to get Nepal
out of places_to_visit
using both a
positive and negative number for the index.
Modifying
Lists are mutable. This means that once created, you can change their contents and Python will just work with the updated list. You can change a list a number of ways:
- Setting a value in the list explicitly with
[n]
wheren
is the index you want to change. - Using a method
of the
list
object like.append()
or.pop()
There’s a lot that you can do with lists, so much that we simply can’t cover it all here, so instead here are some examples, and a link to the documentation for a more complete reference:
>>> print(places_to_visit)
['Mexico', 'Portugal', 'Kenya', 'Nepal', 'New Zealand']
>>> places_to_visit = ['Mexico', 'Portugal', 'Kenya', 'Nepal', 'New Zealand']
>>> places_to_visit[1] = "Peru"
>>> print(places_to_visit)
['Mexico', 'Peru', 'Kenya', 'Nepal', 'New Zealand']
>>> places_to_visit = ['Mexico', 'Portugal', 'Kenya', 'Nepal', 'New Zealand']
>>> print(places_to_visit.pop())
'New Zealand'
>>> print(places_to_visit)
['Mexico', 'Portugal', 'Kenya', 'Nepal']
>>> places_to_visit = ['Mexico', 'Portugal', 'Kenya', 'Nepal', 'New Zealand']
>>> places_to_visit.append("Colombia")
>>> print(places_to_visit)
['Mexico', 'Portugal', 'Kenya', 'Nepal', 'New Zealand', 'Colombia']
Try some of these out yourself:
- Try adding a country to a list with
.append()
. - Take a look at the documentation and try out some of the other methods.
.count()
is a simple one, and.reverse()
is handy to know.
Subsets
But we’re not finished! You can do even more interesting things with [
and
]
on a list, like getting a subset of your data. Say for example you wanted
to get the first four elements of a list as another list. That’s easy with
the subset syntax:
>>> print(places_to_visit[0:4])
["Mexico", "Portugal", "Kenya", "Nepal"]
>>> print(places_to_visit[:4])
["Mexico", "Portugal", "Kenya", "Nepal"]
You can do some interesting things with negative numbers too:
>>> print(places_to_visit[-3:4])
['Portugal', 'Kenya', 'Nepal']
>>> print(places_to_visit[-3:])
['Portugal', 'Kenya', 'Nepal']
…and as getting a subset returns a list itself, you can get a subset of a subset:
>>> print(places_to_visit[0:4][-1])
'Nepal'
Nesting
The last list-related thing we’ll cover here is that there’s nothing stopping you from putting a list inside a list. In fact, you can put a list inside a list, inside a list, inside a… you get the idea. You’re only limited by how many levels deep you can go before your code is too confusing:
>>> cake_flavours = ["chocolate", ["chocolate", "vanilla"], "red velvet"]
>>> print(cake_flavours[0])
'chocolate'
>>> print(cake_flavours[1])
['chocolate', 'vanilla']
>>> print(cake_flavours[1][1])
'vanilla'
There’s a lot more things you can do with lists including concatenating, diffing, sorting, and (scary, but fun) subclassing. This is enough to get you started though.
Tuples
Tuples are a lot like lists with one key exception: they’re immutable. This
means that you can create them, reference them with all of the indexing tricks
mentioned above, but you can’t modify them. Any attempts to modify a tuple
will result in a TypeError
.
Tuples are represented using (
and )
:
>>> places_to_visit = ("Mexico", "Portugal", "Kenya", "Nepal", "New Zealand")
>>> print(places_to_visit[1])
'Portugal'
>>> print(places_to_visit[0:3])
('Mexico', 'Portugal', 'Kenya')
This however will fail with a TypeError
:
>>> places_to_visit[1] = "Canada"
Tuples are commonly used in cases where you’re defining something that shouldn’t ever change, but should you ever need to modify something that’s in a tuple, you can always cast it as a list:
>>> my_tuple = (1, 2, 3)
>>> my_list = list(my_tuple)
>>> my_list[2] = 99
>>> print(my_list)
[1, 2, 99]
>>> print(my_tuple)
(1, 2, 3)
This will make a copy of the tuple that’s a list, so you can edit it, but the tuple itself will remain unchanged.
Take some time to experiment with tuples and get comfortable with the limitations. Try to create one, and watch how Python will explode when you try to modify it. Then try casting a tuple as a list and a list as a tuple.
Dictionaries
Sometimes called “associative arrays” or “hashmaps” by people coming from other languages, Python’s dictionaries are a simple way to store keys and their corresponding values. You’ll often seen them as a simple way to have a lookup table or crude database in an application. For this tutorial we’ll use a dictionary for a phone book:
>>> my_phone_book = {
"Arya": "+4407485376242",
"Brienne": "+3206785246863",
"Cersei": "+14357535455",
"Davos": "+244562726258"
}
As you can see, where lists use [
and ]
, dictionaries use {
and }
and
then separate the keys & values with a :
. The addressing style is similar
though. This will give you Cersei’s phone number:
my_phone_book["Cersei"]
There’s nothing restricting you to strings as values in your dictionary though. You can have anything in there:
>>> my_crazy_dictionary = {
"a number": 7,
"a float": 1.23456789,
"a string": "hello, world!",
"a list": ["This", "is my", "list"],
"another dictionary!": {
"Arya": "+4407485376242",
"Brienne": "+3206785246863",
"Cersei": "+14357535455",
"Davos": "+244562726258"
}
}
Actually, you can have all kinds of keys: tuples, even functions and classes can be used for keys, though this can sometimes lead to reduced readability, so use this with caution. For example, while this is valid Python, it’s not exactly easy to understand:
>>> my_unreadable_dictionary = {
("this", "is", "a", "tuple!"): {"a string": "hello, world!"}
}
You can’t however use a list or a dictionary as a key, which is probably a good thing ‘cause that’d be super confusing.
Your turn: try creating a dictionary or two of your own. Try using different
types as keys and values, and then try to access them using the standard
my_dictionary["my key"]
syntax.
Modifying
Like lists, dictionaries are mutable, so you can change the values associated with keys, add a key/value pair, or remove a pair altogether. The means of doing this should hopefully feel intuitive by now:
Change a value for a key:
>>> my_phone_book["Brienne"] = "+830685432195"
Add a new key/value pair:
>>> my_phone_book["Ellaria"] = "+560538942621"
This one is new: delete a key/value pair:
>>> del(my_phone_book["Ellaria"])
Now that you’ve got the tools to change your dictionaries, give a shot yourself. Try changing Cersei’s phone number. In fact, change it to a list of phone numbers, and then add a character you love… and then delete them :-(
.keys(), .values() and .items()
Dictionaries are useful structures for your data, but after using them for a
while, you’ll soon find that you’ll want to break them up into specific
manageable parts. Thankfully, Python has you covered with .keys()
,
.values()
, and .items()
. Let’s work with some examples:
>>> my_phone_book = {
"Arya": "+4407485376242",
"Brienne": "+3206785246863",
"Cersei": "+14357535455",
"Davos": "+244562726258"
}
>>> print(my_phone_book.keys())
dict_keys(['Arya', 'Brienne', 'Cersei', 'Davos'])
>>> print(my_phone_book.values())
dict_values(['+4407485376242', '+3206785246863', '+14357535455', '+244562726258'])
>>> print(my_phone_book.items())
dict_items([('Arya', '+4407485376242'), ('Brienne', '+3206785246863'), ('Cersei', '+14357535455'), ('Davos', '+244562726258')])
Important: dictionaries are unordered, which means that while it may seem reasonable that you’ve defined
my_phone_book
above with the keys ordered alphabetically, that’s not now how Python stores them, so the results above may differ in order from your output. Typically if you need your dictionary to be ordered, you’ll use a list of lists, or anOrderedDict
(a topic for another day).
As you can see, .keys()
and .values()
do what you’d expect: they return the
keys and values respectively. You may have noticed however that rather than a
list
or a tuple
, these methods return dict_keys
and dict_values
types.
These are sort of like tuples: you can’t edit them, and if you want to do
anything with them other than read them as a complete entity, you’ll have to
cast them as a list:
>>> print(list(my_phone_book.values()))
['+4407485376242', '+3206785246863', '+14357535455', '+244562726258']
>>> print(list(my_phone_book.values())[3])
'+244562726258'
The last one there, .items()
is interesting. It returns all of the data in
your dictionary, but dumps it out as dict_items
which is a sort of tuple of
tuples. This allows you to reference your dictionary with list syntax:
>>> print(tuple(my_phone_book.items())[1])
('Brienne', '+3206785246863')
>>> print(tuple(my_phone_book.items())[1][1])
'+3206785246863'
Truth be told though, you probably won’t be accessing these values directly
like this. These methods come in handy inside flow control statements like
for
and while
, where you can do things like loop over all of the items in
my_phone_book.items()
and do different things to the keys vs. the values.
That’s for another lesson though.