So far we’ve seen how Variables can hold single values like strings, numbers, or booleans. Python also offers a variety of ‘collections’ that allow you to group bits and pieces of information that belong together and store them in a single variable. The two collection types you’re most likely to find useful are:

Lists

A list in Python is no different from a list in real life: it can hold a summary of stuff to do, groceries to buy, a sheet of names and adressess. The main difference is that in real life we usually start counting from one, while lists in Python start from zero:

Creating a list

So, what would the code equivalent of our grocery list look like? Below we’ve defined it as a Python list object. The list is defined between square brackets. Each item in the list is a piece of text (a string) surrounded by quotes, and is separated from its neighbors by commas. The list is assigned to a variable named groceries, but we know that variables can have any name we like, so it could just as easily be named g or stufftodo.

groceries = ["milk", "eggs", "tabasco", "brussel sprouts", "bacon", "pistachios"]

A list can contain any kind of data: strings, numbers, and even other lists. The len() command returns the number of items in a list:

print(len(groceries))
>>> 6

Retrieving and editing items in a list

You can reference items in a list directly using ‘index notation’. Place a pair of square brackets after the variable name with a numerical index between them:

print(groceries[0])
>>> milk
groceries[2] = "habanero sauce"
print(groceries)
>>> ["milk", "eggs", "habanero sauce", "brussel sprouts", "bacon", "pistachios"]

Don’t forget that items in a list start at index zero. That’s why index ‘2’ in the example above causes the third element to be replaced. You can also pull items from the end of the list by using negative index values to count backwards from the last item. The last element in a list is -1, the second-to-last is -2, and so on:

print("final item:", groceries[-1])
print("penultimate:", groceries[-2])
>>> final item: pistachios
>>> penultimate: bacon

Adding and removing items

The contents of a list can be changed over time. New items can be added to it or old items deleted from it – just like you can add entries to a grocery list and cross them out once they’ve been picked up.

You can add a new item to the end of a list with the append() method:

groceries.append("tea")
print(groceries)
>>> ["milk", "eggs", "habanero sauce", "brussel sprouts",
>>> "bacon", "pistachios", "tea"]

To remove the tea from the list, use the del statement with the proper index:

del groceries[6]

Items can be inserted partway through the list with the list.insert(i, item) command, where the i parameter is the position where you want the element to be. Rather than overwriting the item that’s currently the i’th element, the old items will be shifted back to make room for the insertion.

Iteration

Looping through a list is a bit like going to the market and working through your grocery list from top to bottom: the first item to collect is milk, next you’ll need to fetch eggs, and so on.

Going through all the items in a list is one of the most essential things you do when working with data. You could retrieve the items in a list manually when there are only a few of them, but not when the list contains hundreds or even thousands of, for example, strings of text that you want to draw to the screen.

When you use a for-loop with a list, any indented commands below the for statement are executed for each item in the list. The item variable consecutively contains each item in the list. Once it reaches the last item in the list, the loop ends:

print("walk to the market")
for item in groceries:
    print("buy some", item)
print("done shopping!")
>>> walk to the market
>>> buy some milk
>>> buy some eggs
>>> buy some habanero sauce
>>> buy some brussel sprouts
>>> buy some bacon
>>> buy some pistachios
>>> done shopping!

Further reading

There’s a lot more you can do with lists, like sorting and reversing, retrieving a range of elements as a slice, or using functional-programming concepts like ‘map’ and ‘filter’ in a list comprehension. The Python tutorial on Datastructures will get you started with some of the more advanced features of the list object.

Dictionaries

A dictionary (or ‘dict’) is an extremely versatile kind of list that lets you access elements via indices (known as ‘keys’) that you define yourself. Each key is unique and references an item stored in the dict. Unlike list indices, which are always integers, dictionary keys can be any datatype you want. String-based keys are a popular choice, but you could just as easily use numbers, booleans, or even tuples.

Dictionaries are created with curly braces instead of square brackets. You can assign and retrieve values from a dictionary using the same ‘index’ syntax as for lists:

heading = {}
heading["family"] = "Avenir Next"
heading["size"] = 18
heading["fill"] = color(1,0,0)

print(heading["size"])
print(heading["fill"])
>>> 18
>>> Color('#f00')

You can also initialize a dictionary in a single step by defining the keys and values inside the curly braces. Note that unlike other languages with similar syntax (e.g., javascript), keys must be enclosed in quotes or they will be interpreted as variable names rather than strings:

heading = {
    "family":"Avenir Next",
    "size":18,
    "fill":color(1,0,0)
}

If this sounds like too much punctuation, consider using the dict() command which lets you specify keys through keyword arguments:

heading = dict(family="Avenir Next", size=18, fill=color(1,0,0))

Dictionaries are ‘random access’

While the elements in a list have an implicit order, there’s no obvious way to decide what the ‘next’ element in a dictionary should be. Instead you can think of the dictionary as a soup of key/value pairs. To get a list of all the keys that have been added to a dictionary, use its keys() method. Note that the order of the keys has no relation to the order in which you defined them:

print(list(heading.keys()))
>>> ["family", "fill", "size"] # even though we defined it with family, size, fill

If it’s important for the key order to be preserved, you can use an odict (a.k.a. an Ordered Dictionary) object instead.

Dealing with missing values

To test whether a particular key has been defined in a dict, use an ’if … in’ statement.

if "fill" in heading:
    print("found fill!")
if "italic" not in heading:
    print("italic not defined...")
>>> found fill!
>>> italic not defined...

It’s important to be sure your dict has the expected keys since any attempt to read from an undefined key will crash your script with a KeyError exception:

print heading["italic"]
>>> KeyError: 'italic'

Undefined keys are actually a rather common occurrance, so having a missing value cause a fatal error is a little harsh. Luckily Python offers a way to read keys ‘safely’ by using the dict.get() method. Call get() with a pair of arguments: the key name and a ‘default’ value to be returned if the dictionary doesn’t contain that key:

print("fam:", heading.get("family", "Helvetica")) # key exists, default ignored
print("wgt:", heading.get("weight", "normal")) # undefined, default used instead
>>> fam: Avenir Next
>>> wgt: normal

Specialized dictionaries

The standard dictionary object provided by the built-in dict type will suit your needs the vast majority of the time. There are three dictionary variants that may also come in handy:

Consult the Reference entries for these types to learn when they’re useful and what caveats apply to each.