{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "###### The cell above loads the visual style of the notebook when run." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "" ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.core.display import HTML\n", "css_file = '../styles.css'\n", "HTML(open(css_file, \"r\").read())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Storing multiple values in lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "

Learning Objectives

\n", "
\n", "
\n", "\n", "> * Explain what a list is.\n", "> * Create and index lists of simple values." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just as a `for` loop is a way to do operations many times, a list is a way to store many values. Unlike NumPy arrays, lists are built into the language (so we don't have to load a library to use them).\n", "\n", "We create a list by putting values inside square brackets:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Odd numbers are: [1, 3, 5, 7]\n" ] } ], "source": [ "odds = [1,3,5,7]\n", "print ('Odd numbers are:',odds)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We select individual elements from lists by indexing them: " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "first and last: 1 7\n" ] } ], "source": [ "print ('first and last:', odds[0], odds[-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "and if we loop over a list, the loop variable is assigned elements one at a time: " ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n", "3\n", "5\n", "7\n" ] } ], "source": [ "for number in odds:\n", " print(number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is one important difference between lists and strings: we can change the values in a list, but we cannot change the characters in a string.\n", "\n", "For example:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "names is originally: ['Newton', 'Darwing', 'Turing']\n", "final value of names: ['Newton', 'Darwin', 'Turing']\n" ] } ], "source": [ "names = ['Newton', 'Darwing', 'Turing'] # typo in Darwin's name\n", "print ('names is originally:', names)\n", "names[1] = 'Darwin' # correct the name\n", "print ('final value of names:', names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "works, but:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "ename": "TypeError", "evalue": "'str' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'Bell'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mname\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'b'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'str' object does not support item assignment" ] } ], "source": [ "name = 'Bell'\n", "name[0] = 'b'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "doesn't!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "

Changes

\n", "
\n", "
\n", "\n", "> Data which can be modified in place is called [mutable](reference.html#mutable),\n", "> while data which cannot be modified is called [immutable](reference.html#immutable).\n", "> Strings and numbers are immutable. This does not mean that variables with string or number values are constants,\n", "> but when we want to change the value of a string or number variable, we can only replace the old value \n", "> with a completely new value. For example, consider the diagram below, which shows what happens when we change the value of an immutable variable.\n", "> \n", ">
Figure: Changing immutable objects
\n", ">\n", "> Lists and arrays, on the other hand, are mutable: we can modify them after they have been created. We can \n", "> change individual elements, append new elements, or reorder the whole list. For some operations, like \n", "> sorting, we can choose whether to use a function that modifies the data *in place* or a function that returns a \n", "> modified copy and leaves the original unchanged. Consider the diagram below, which illustrates changing a list in place.\n", ">\n", "> \n", ">
Figure: In-place change to mutable object
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "

Check your understanding

\n", "
\n", "
\n", "\n", "> Look at the code below. What do you expect it to do? Check your answer with the person next to you. \n", "\n", "> ```python\n", "ages = [20,23,18,30]\n", "new_ages = ages\n", "new_ages[1] = 64\n", "print(ages)\n", "```\n", "\n", "> Now run the code in the cell below. Does it do what you expect?\n", "\n", "---" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[20, 64, 18, 30]\n" ] } ], "source": [ "ages = [20,23,18,30]\n", "new_ages = ages\n", "new_ages[1] = 64\n", "print(ages)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "

Mutability and copies

\n", "
\n", "
\n", "\n", "> In Python, the statement `new_ages = ages` doesn't make a **copy** of `ages`. Instead, it adds a new label to the same bit of computer memory. You can think of this like putting two sticky labels on the same box. This has important consequences for mutable objects like lists." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import HTML\n", "HTML('')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> When you modify `new_ages`, you're changing the memory that `ages` is looking at. If you want variables with mutable values to be independent, you must make a copy of the value when you assign it. You can use the built-in `list()` command to create a new list, so we do not modify a list we did not mean to \n", "\n", ">```python\n", "new_ages = list(ages)\n", "```\n", "\n", "> Because of pitfalls like this, code which modifies data in place can be very difficult to understand! If you find yourself having trouble with variables changing when you don't expect, or vice-versa, you've likely fallen foul of this subtlety. It can be very useful to try out your code at [pythontutor.com](http://pythontutor.com) - this will produce diagrams like the ones above to help you visualise how variables are being assigned and changed. If you are interested in understanding this concept more fully, I can strongly recommend the excellent talk [here](http://nedbatchelder.com/text/names1.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many ways to change the contents of lists besides assigning new values to individual elements. Let's look at some of them briefly:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Odd numbers after adding a value: [1, 3, 5, 7, 11]\n" ] } ], "source": [ "odds = [1,3,5,7]\n", "odds.append(11)\n", "print ('Odd numbers after adding a value:', odds)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Odd numbers after removing the first element: [3, 5, 7, 11]\n" ] } ], "source": [ "del odds[0]\n", "print ('Odd numbers after removing the first element:', odds)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Odd numbers after reversing: [11, 7, 5, 3]\n" ] } ], "source": [ "odds.reverse()\n", "print ('Odd numbers after reversing:', odds)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "

Unpacking from lists

\n", "
\n", "
\n", "\n", "> Python has a really neat syntax for getting values back out of a list. For example, the following code unpacks values from a list of planet masses" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Saturn's mass is 95.2 Earth masses\n" ] } ], "source": [ "# planet masses in units of Earth's mass\n", "planet_masses = [0.0553, 0.815, 0.107, 317.8, 95.2]\n", "\n", "mercury, venus, mars, jupiter, saturn = planet_masses\n", "\n", "print (\"Saturn's mass is \", saturn, \" Earth masses\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "

Turn a string into a list

\n", "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ">Use a for-loop to convert the string \"hello\" into a list of letters:\n", "\n", ">```python\n", "[\"h\", \"e\", \"l\", \"l\", \"o\"]\n", "```\n", "\n", ">Hint: You can create an empty list like this:\n", "\n", ">```python\n", "my_list = []\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# INSERT YOUR CODE HERE" ] } ], "metadata": { "kernelspec": { "display_name": "IPython (Python 3)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.3" } }, "nbformat": 4, "nbformat_minor": 0 }