Skip to content

Instantly share code, notes, and snippets.

@damontallen
Created July 4, 2013 18:16
Show Gist options
  • Save damontallen/5929466 to your computer and use it in GitHub Desktop.
Save damontallen/5929466 to your computer and use it in GitHub Desktop.
A Crash Course in Python for Scientists (in four parts)
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": "Crash Course v0.5a"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# A Crash Course in Python for Scientists\n",
"[Rick Muller](http://www.cs.sandia.gov/~rmuller/), Sandia National Laboratories\n",
"\n",
"version 0.5, Released 7/3/2013, Alpha\n",
"\n",
"This work is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/deed.en_US)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Why Python?\n",
"Python is the programming language of choice for many scientists to a large degree because it offers a great deal of power to analyze and model scientific data with relatively little overhead in terms of learning, installation or development time. It is a language you can pick up in a weekend, and use for the rest of one's life.\n",
"\n",
"The [Python Tutorial](http://docs.python.org/2/tutorial/) is a great place to start getting a feel for the language. To complement this material, I taught a [Python Short Course](http://www.wag.caltech.edu/home/rpm/python_course/) years ago to a group of computational chemists during a time that I was worried the field was moving too much in the direction of using canned software rather than developing one's own methods. I wanted to focus on what working scientists needed to be more productive: parsing output of other programs, building simple models, experimenting with object oriented programming, extending the language with C, and simple GUIs. \n",
"\n",
"I'm trying to do something very similar here, to cut to the chase and focus on what scientists need. In the last year or so, the [IPython Project](http://ipython.org) has put together a notebook interface that I have found incredibly valuable. A large number of people have released very good IPython Notebooks that I have taken a huge amount of pleasure reading through. Some ones that I particularly like include:\n",
"\n",
"* Rob Johansson's [excellent notebooks](http://jrjohansson.github.io/), including [Scientific Computing with Python](https://github.com/jrjohansson/scientific-python-lectures) and [Computational Quantum Physics with QuTiP](https://github.com/jrjohansson/qutip-lectures) lectures;\n",
"* [XKCD style graphs in matplotlib](http://nbviewer.ipython.org/url/jakevdp.github.com/downloads/notebooks/XKCD_plots.ipynb);\n",
"* [A collection of Notebooks for using IPython effectively](https://github.com/ipython/ipython/tree/master/examples/notebooks#a-collection-of-notebooks-for-using-ipython-effectively)\n",
"* [A gallery of interesting IPython Notebooks](https://github.com/ipython/ipython/wiki/A-gallery-of-interesting-IPython-Notebooks)\n",
"\n",
"I find IPython notebooks an easy way both to get important work done in my everyday job, as well as to communicate what I've done, how I've done it, and why it matters to my coworkers. I find myself endlessly sweeping the [IPython subreddit](http://ipython.reddit.com) hoping someone will post a new notebook. In the interest of putting more notebooks out into the wild for other people to use and enjoy, I thought I would try to recreate some of what I was trying to get across in the original Python Short Course, updated by 15 years of Python, Numpy, Scipy, Matplotlib, and IPython development, as well as my own experience in using Python almost every day of this time."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## What You Need to Install\n",
"\n",
"There are two branches of current releases in Python: the older-syntax Python 2, and the newer-syntax Python 3. This schizophrenia is largely intentional: when it became clear that some non-backwards-compatible changes to the language were necessary, the Python dev-team decided to go through a five-year (or so) transition, during which the new language features would be introduced and the old language was still actively maintained, to make such a transition as easy as possible. We're now (2013) past the halfway point, and, IMHO, at the first time when I'm considering making the change to Python 3.\n",
"\n",
"With this in mind, these notes assume you have a Python distribution that includes:\n",
"\n",
"* [Python](http://www.python.org) version 3.2;\n",
"* [Numpy](http://www.numpy.org), the core numerical extensions for linear algebra and multidimensional arrays;\n",
"* [Scipy](http://www.scipy.org), additional libraries for scientific programming;\n",
"* [Matplotlib](http://matplotlib.sf.net), excellent plotting and graphing libraries;\n",
"* [IPython](http://ipython.org), with the additional libraries required for the notebook interface.\n",
"\n",
"A good, easy to install option that supports Mac, Windows, and Linux, and that has all of these packages (and much more) is the [Entought Python Distribution](https://www.enthought.com/products/epd), also known as EPD, which appears to be changing its name to Enthought Canopy. Enthought is a commercial company that supports a lot of very good work in scientific Python development and application. You can either purchase a license to use EPD, or there is also a [free version](https://www.enthought.com/products/epd/free/) that you can download and install.\n",
"\n",
"Here are some other alternatives, should you not want to use EPD:\n",
"\n",
"**Linux** Most distributions have an installation manager. Redhat has yum, Ubuntu has apt-get. To my knowledge, all of these packages should be available through those installers.\n",
"\n",
"**Mac** I use [Macports](http://www.macports.org/), which has up-to-date versions of all of these packages.\n",
"\n",
"**Windows** The [PythonXY](https://code.google.com/p/pythonxy/) package has everything you need: install the package, then go to Start > PythonXY > Command Prompts > IPython notebook server.\n",
"\n",
"**Cloud** This notebook is currently not running on the [IPython notebook viewer](http://nbviewer.ipython.org/), but will be shortly, which will allow the notebook to be viewed but not interactively. I'm keeping an eye on [Wakari](http://www.wakari.io), from [Continuum Analytics](http://continuum.io/), which is a cloud-based IPython notebook. Wakari appears to support free accounts as well. Continuum is a company started by some of the core Enthought Numpy/Scipy people focusing on big data. \n",
"\n",
"Continuum also supports a bundled, multiplatform Python package called [Anaconda](https://store.continuum.io/) that I'll also keep an eye on."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# I. Python Overview\n",
"This is a quick introduction to Python. There are lots of other places to learn the language more thoroughly. I have collected a list of useful links, including ones to other learning resources, at the end of this notebook. If you want a little more depth, [Python Tutorial](http://docs.python.org/2/tutorial/) is a great place to start, as is Zed Shaw's [Learn Python the Hard Way](http://learnpythonthehardway.org/book/).\n",
"\n",
"The lessons that follow make use of the IPython notebooks. There's a good introduction to notebooks [in the IPython notebook documentation](http://ipython.org/notebook.html) that even has a [nice video](http://www.youtube.com/watch?v=H6dLGQw9yFQ#!) on how to use the notebooks. You should probably also flip through the [IPython tutorial](http://ipython.org/ipython-doc/dev/interactive/tutorial.html) in your copious free time.\n",
"\n",
"Briefly, notebooks have code cells (that are generally followed by result cells) and text cells. The text cells are the stuff that you're reading now. The code cells start with \"In []:\" with some number generally in the brackets. If you put your cursor in the code cell and hit Shift-Enter, the code will run in the Python interpreter and the result will print out in the output cell. You can then change things around and see whether you understand what's going on. If you need to know more, see the [IPython notebook documentation](http://ipython.org/notebook.html) or the [IPython tutorial](http://ipython.org/ipython-doc/dev/interactive/tutorial.html)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using Python as a Calculator"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Many of the things I used to use a calculator for, I now use Python for:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"2+2"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 1,
"text": [
"4"
]
}
],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"(50-5*6)/4"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 2,
"text": [
"5.0"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(If you're typing this into an IPython notebook, or otherwise using notebook file, you hit shift-Enter to evaluate a cell.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are some gotchas compared to using a normal calculator."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"7/3"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 3,
"text": [
"2.3333333333333335"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python integer division, like C or Fortran integer division, truncates the remainder and returns an integer. At least it does in version 2. In version 3, Python returns a floating point number. You can get a sneak preview of this feature in Python 2 by importing the module from the future features:\n",
"\n",
" from __future__ import division"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Alternatively, you can convert one of the integers to a floating point number, in which case the division function returns another floating point number."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"7/3."
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 4,
"text": [
"2.3333333333333335"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"7/float(3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 5,
"text": [
"2.3333333333333335"
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the last few lines, we have sped by a lot of things that we should stop for a moment and explore a little more fully. We've seen, however briefly, two different data types: **integers**, also known as *whole numbers* to the non-programming world, and **floating point numbers**, also known (incorrectly) as *decimal numbers* to the rest of the world.\n",
"\n",
"We've also seen the first instance of an **import** statement. Python has a huge number of libraries included with the distribution. To keep things simple, most of these variables and functions are not accessible from a normal Python interactive session. Instead, you have to import the name. For example, there is a **math** module containing many useful functions. To access, say, the square root function, you can either first\n",
"\n",
" from math import sqrt\n",
"\n",
"and then"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sqrt(81)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 6,
"text": [
"9.0"
]
}
],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"or you can simply import the math library itself"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import math\n",
"math.sqrt(81)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 7,
"text": [
"9.0"
]
}
],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can define variables using the equals (=) sign:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"width = 20\n",
"length = 30\n",
"area = length*width\n",
"area"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 8,
"text": [
"600"
]
}
],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you try to access a variable that you haven't yet defined, you get an error:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"volume"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'volume' is not defined",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-9-0c7fc58f9268>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mvolume\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mNameError\u001b[0m: name 'volume' is not defined"
]
}
],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"and you need to define it:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"depth = 10\n",
"volume = area*depth\n",
"volume"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 10,
"text": [
"6000"
]
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can name a variable *almost* anything you want. It needs to start with an alphabetical character or \"\\_\", can contain alphanumeric charcters plus underscores (\"\\_\"). Certain words, however, are reserved for the language:\n",
"\n",
" and, as, assert, break, class, continue, def, del, elif, else, except, \n",
" exec, finally, for, from, global, if, import, in, is, lambda, not, or,\n",
" pass, print, raise, return, try, while, with, yield\n",
"\n",
"Trying to define a variable using one of these will result in a syntax error:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"return = 0"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "SyntaxError",
"evalue": "invalid syntax (<ipython-input-11-2b99136d4ec6>, line 1)",
"output_type": "pyerr",
"traceback": [
"\u001b[0;36m File \u001b[0;32m\"<ipython-input-11-2b99136d4ec6>\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m return = 0\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"
]
}
],
"prompt_number": 11
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The [Python Tutorial](http://docs.python.org/2/tutorial/introduction.html#using-python-as-a-calculator) has more on using Python as an interactive shell. The [IPython tutorial](http://ipython.org/ipython-doc/dev/interactive/tutorial.html) makes a nice complement to this, since IPython has a much more sophisticated iteractive shell."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Strings\n",
"Strings are lists of printable characters, and can be defined using either single quotes"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"'Hello, World!'"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 12,
"text": [
"'Hello, World!'"
]
}
],
"prompt_number": 12
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"or double quotes"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"Hello, World!\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 13,
"text": [
"'Hello, World!'"
]
}
],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But not both at the same time, unless you want one of the symbols to be part of the string."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"He's a Rebel\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 14,
"text": [
"\"He's a Rebel\""
]
}
],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"'She asked, \"How are you today?\"'"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 15,
"text": [
"'She asked, \"How are you today?\"'"
]
}
],
"prompt_number": 15
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Just like the other two data objects we're familiar with (ints and floats), you can assign a string to a variable"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"greeting = \"Hello, World!\""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 16
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The **print** statement is often used for printing character strings:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(greeting)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Hello, World!\n"
]
}
],
"prompt_number": 17
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But it can also print data types other than strings:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print(\"The area is \",area)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"The area is 600\n"
]
}
],
"prompt_number": 18
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the above snipped, the number 600 (stored in the variable \"area\") is converted into a string before being printed out."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can use the + operator to concatenate strings together:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"statement = \"Hello,\" + \"World!\"\n",
"print(statement)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Hello,World!\n"
]
}
],
"prompt_number": 19
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Don't forget the space between the strings, if you want one there. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"statement = \"Hello, \" + \"World!\"\n",
"print(statement)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Hello, World!\n"
]
}
],
"prompt_number": 20
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can use + to concatenate multiple strings in a single statement:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print( \"This \" + \"is \" + \"a \" + \"longer \" + \"statement.\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"This is a longer statement.\n"
]
}
],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you have a lot of words to concatenate together, there are other, more efficient ways to do this. But this is fine for linking a few strings together."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Lists\n",
"Very often in a programming language, one wants to keep a group of similar items together. Python does this using a data type called **lists**."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week = [\"Sunday\",\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\"]"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 22
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can access members of the list using the **index** of that item:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week[2]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 23,
"text": [
"'Tuesday'"
]
}
],
"prompt_number": 23
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python lists, like C, but unlike Fortran, use 0 as the index of the first element of a list. Thus, in this example, the 0 element is \"Sunday\", 1 is \"Monday\", and so on. If you need to access the *n*th element from the end of the list, you can use a negative index. For example, the -1 element of a list is the last element:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week[-1]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 24,
"text": [
"'Saturday'"
]
}
],
"prompt_number": 24
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can add additional items to the list using the .append() command:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"languages = [\"Fortran\",\"C\",\"C++\"]\n",
"languages.append(\"Python\")\n",
"print(languages)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['Fortran', 'C', 'C++', 'Python']\n"
]
}
],
"prompt_number": 25
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The **range()** command is a convenient way to make sequential lists of numbers:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list(range(10))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 26,
"text": [
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
]
}
],
"prompt_number": 26
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that range(n) starts at 0 and gives the sequential list of integers less than n. If you want to start at a different number, use range(start,stop)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list(range(2,8))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 27,
"text": [
"[2, 3, 4, 5, 6, 7]"
]
}
],
"prompt_number": 27
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The lists created above with range have a *step* of 1 between elements. You can also give a fixed step size via a third command:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"evens = list(range(0,20,2))\n",
"evens"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 28,
"text": [
"[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]"
]
}
],
"prompt_number": 28
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"evens[3]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 29,
"text": [
"6"
]
}
],
"prompt_number": 29
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lists do not have to hold the same data type. For example,"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"[\"Today\",7,99.3,\"\"]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 30,
"text": [
"['Today', 7, 99.3, '']"
]
}
],
"prompt_number": 30
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However, it's good (but not essential) to use lists for similar objects that are somehow logically connected. If you want to group different data types together into a composite data object, it's best to use **tuples**, which we will learn about below.\n",
"\n",
"You can find out how long a list is using the **len()** command:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"help(len)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on built-in function len in module builtins:\n",
"\n",
"len(...)\n",
" len(object) -> integer\n",
" \n",
" Return the number of items of a sequence or mapping.\n",
"\n"
]
}
],
"prompt_number": 31
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"len(evens)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 32,
"text": [
"10"
]
}
],
"prompt_number": 32
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Iteration, Indentation, and Blocks\n",
"One of the most useful things you can do with lists is to *iterate* through them, i.e. to go through each element one at a time. To do this in Python, we use the **for** statement:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for day in days_of_the_week:\n",
" print(day)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Sunday\n",
"Monday\n",
"Tuesday\n",
"Wednesday\n",
"Thursday\n",
"Friday\n",
"Saturday\n"
]
}
],
"prompt_number": 33
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This code snippet goes through each element of the list called **days_of_the_week** and assigns it to the variable **day**. It then executes everything in the indented block (in this case only one line of code, the print statement) using those variable assignments. When the program has gone through every element of the list, it exists the block.\n",
"\n",
"(Almost) every programming language defines blocks of code in some way. In Fortran, one uses END statements (ENDDO, ENDIF, etc.) to define code blocks. In C, C++, and Perl, one uses curly braces {} to define these blocks.\n",
"\n",
"Python uses a colon (\":\"), followed by indentation level to define code blocks. Everything at a higher level of indentation is taken to be in the same block. In the above example the block was only a single line, but we could have had longer blocks as well:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for day in days_of_the_week:\n",
" statement = \"Today is \" + day\n",
" print(statement)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Today is Sunday\n",
"Today is Monday\n",
"Today is Tuesday\n",
"Today is Wednesday\n",
"Today is Thursday\n",
"Today is Friday\n",
"Today is Saturday\n"
]
}
],
"prompt_number": 34
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The **range()** command is particularly useful with the **for** statement to execute loops of a specified length:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for i in range(20):\n",
" print(\"The square of \",i,\" is \",i*i)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"The square of 0 is 0\n",
"The square of 1 is 1\n",
"The square of 2 is 4\n",
"The square of 3 is 9\n",
"The square of 4 is 16\n",
"The square of 5 is 25\n",
"The square of 6 is 36\n",
"The square of 7 is 49\n",
"The square of 8 is 64\n",
"The square of 9 is 81\n",
"The square of 10 is 100\n",
"The square of 11 is 121\n",
"The square of 12 is 144\n",
"The square of 13 is 169\n",
"The square of 14 is 196\n",
"The square of 15 is 225\n",
"The square of 16 is 256\n",
"The square of 17 is 289\n",
"The square of 18 is 324\n",
"The square of 19 is 361\n"
]
}
],
"prompt_number": 35
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Slicing\n",
"Lists and strings have something in common that you might not suspect: they can both be treated as sequences. You already know that you can iterate through the elements of a list. You can also iterate through the letters in a string:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for letter in \"Sunday\":\n",
" print(letter)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"S\n",
"u\n",
"n\n",
"d\n",
"a\n",
"y\n"
]
}
],
"prompt_number": 36
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is only occasionally useful. Slightly more useful is the *slicing* operation, which you can also use on any sequence. We already know that we can use *indexing* to get the first element of a list:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week[0]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 37,
"text": [
"'Sunday'"
]
}
],
"prompt_number": 37
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we want the list containing the first two elements of a list, we can do this via"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week[0:2]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 38,
"text": [
"['Sunday', 'Monday']"
]
}
],
"prompt_number": 38
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"or simply"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week[:2]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 39,
"text": [
"['Sunday', 'Monday']"
]
}
],
"prompt_number": 39
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we want the last items of the list, we can do this with negative slicing:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"days_of_the_week[-2:]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 40,
"text": [
"['Friday', 'Saturday']"
]
}
],
"prompt_number": 40
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"which is somewhat logically consistent with negative indices accessing the last elements of the list.\n",
"\n",
"You can do:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"workdays = days_of_the_week[1:6]\n",
"print( workdays)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']\n"
]
}
],
"prompt_number": 41
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since strings are sequences, you can also do this to them:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"day = \"Sunday\"\n",
"abbreviation = day[:3]\n",
"print(abbreviation)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Sun\n"
]
}
],
"prompt_number": 42
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we really want to get fancy, we can pass a third element into the slice, which specifies a step length (just like a third argument to the **range()** function specifies the step):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"numbers = list(range(0,40))\n",
"evens = numbers[2::2]\n",
"evens"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 43,
"text": [
"[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38]"
]
}
],
"prompt_number": 43
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that in this example I was even able to omit the second argument, so that the slice started at 2, went to the end of the list, and took every second element, to generate the list of even numbers less that 40."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Booleans and Truth Testing\n",
"We have now learned a few data types. We have integers and floating point numbers, strings, and lists to contain them. We have also learned about lists, a container that can hold any data type. We have learned to print things out, and to iterate over items in lists. We will now learn about **boolean** variables that can be either True or False.\n",
"\n",
"We invariably need some concept of *conditions* in programming to control branching behavior, to allow a program to react differently to different situations. If it's Monday, I'll go to work, but if it's Sunday, I'll sleep in. To do this in Python, we use a combination of **boolean** variables, which evaluate to either True or False, and **if** statements, that control branching based on boolean values."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For example:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"if day == \"Sunday\":\n",
" print(\"Sleep in\")\n",
"else:\n",
" print(\"Go to work\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Sleep in\n"
]
}
],
"prompt_number": 44
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(Quick quiz: why did the snippet print \"Go to work\" here? What is the variable \"day\" set to?)\n",
"\n",
"Let's take the snippet apart to see what happened. First, note the statement"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"day == \"Sunday\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 45,
"text": [
"True"
]
}
],
"prompt_number": 45
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we evaluate it by itself, as we just did, we see that it returns a boolean value, False. The \"==\" operator performs *equality testing*. If the two items are equal, it returns True, otherwise it returns False. In this case, it is comparing two variables, the string \"Sunday\", and whatever is stored in the variable \"day\", which, in this case, is the other string \"Saturday\". Since the two strings are not equal to each other, the truth test has the false value."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The if statement that contains the truth test is followed by a code block (a colon followed by an indented block of code). If the boolean is true, it executes the code in that block. Since it is false in the above example, we don't see that code executed.\n",
"\n",
"The first block of code is followed by an **else** statement, which is executed if nothing else in the above if statement is true. Since the value was false, this code is executed, which is why we see \"Go to work\".\n",
"\n",
"You can compare any data types in Python:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1 == 2"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 46,
"text": [
"False"
]
}
],
"prompt_number": 46
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"50 == 2*25"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 47,
"text": [
"True"
]
}
],
"prompt_number": 47
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"3 < 3.14159"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 48,
"text": [
"True"
]
}
],
"prompt_number": 48
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1 == 1.0"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 49,
"text": [
"True"
]
}
],
"prompt_number": 49
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1 != 0"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 50,
"text": [
"True"
]
}
],
"prompt_number": 50
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1 <= 2"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 51,
"text": [
"True"
]
}
],
"prompt_number": 51
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1 >= 1"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 52,
"text": [
"True"
]
}
],
"prompt_number": 52
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see a few other boolean operators here, all of which which should be self-explanatory. Less than, equality, non-equality, and so on.\n",
"\n",
"Particularly interesting is the 1 == 1.0 test, which is true, since even though the two objects are different data types (integer and floating point number), they have the same *value*. There is another boolean operator **is**, that tests whether two objects are the same object:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"1 is 1.0"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 53,
"text": [
"False"
]
}
],
"prompt_number": 53
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can do boolean tests on lists as well:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"[1,2,3] == [1,2,4]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 54,
"text": [
"False"
]
}
],
"prompt_number": 54
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"[1,2,3] < [1,2,4]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 55,
"text": [
"True"
]
}
],
"prompt_number": 55
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, note that you can also string multiple comparisons together, which can result in very intuitive tests:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"hours = 5\n",
"0 < hours < 24"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 56,
"text": [
"True"
]
}
],
"prompt_number": 56
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If statements can have **elif** parts (\"else if\"), in addition to if/else parts. For example:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"if day == \"Sunday\":\n",
" print (\"Sleep in\")\n",
"elif day == \"Saturday\":\n",
" print (\"Do chores\")\n",
"else:\n",
" print (\"Go to work\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Sleep in\n"
]
}
],
"prompt_number": 57
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Of course we can combine if statements with for loops, to make a snippet that is almost interesting:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for day in days_of_the_week:\n",
" statement = \"Today is \" + day\n",
" print (statement)\n",
" if day == \"Sunday\":\n",
" print (\" Sleep in\")\n",
" elif day == \"Saturday\":\n",
" print (\" Do chores\")\n",
" else:\n",
" print (\" Go to work\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Today is Sunday\n",
" Sleep in\n",
"Today is Monday\n",
" Go to work\n",
"Today is Tuesday\n",
" Go to work\n",
"Today is Wednesday\n",
" Go to work\n",
"Today is Thursday\n",
" Go to work\n",
"Today is Friday\n",
" Go to work\n",
"Today is Saturday\n",
" Do chores\n"
]
}
],
"prompt_number": 58
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is something of an advanced topic, but ordinary data types have boolean values associated with them, and, indeed, in early versions of Python there was not a separate boolean object. Essentially, anything that was a 0 value (the integer or floating point 0, an empty string \"\", or an empty list []) was False, and everything else was true. You can see the boolean value of any data object using the **bool()** function."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"bool(1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 59,
"text": [
"True"
]
}
],
"prompt_number": 59
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"bool(0)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 60,
"text": [
"False"
]
}
],
"prompt_number": 60
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"bool([\"This \",\" is \",\" a \",\" list\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 61,
"text": [
"True"
]
}
],
"prompt_number": 61
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Code Example: The Fibonacci Sequence\n",
"The [Fibonacci sequence](http://en.wikipedia.org/wiki/Fibonacci_number) is a sequence in math that starts with 0 and 1, and then each successive entry is the sum of the previous two. Thus, the sequence goes 0,1,1,2,3,5,8,13,21,34,55,89,...\n",
"\n",
"A very common exercise in programming books is to compute the Fibonacci sequence up to some number **n**. First I'll show the code, then I'll discuss what it is doing."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"n = 10\n",
"sequence = [0,1]\n",
"for i in range(2,n): # This is going to be a problem if we ever set n <= 2!\n",
" sequence.append(sequence[i-1]+sequence[i-2])\n",
"print (sequence)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]\n"
]
}
],
"prompt_number": 62
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's go through this line by line. First, we define the variable **n**, and set it to the integer 20. **n** is the length of the sequence we're going to form, and should probably have a better variable name. We then create a variable called **sequence**, and initialize it to the list with the integers 0 and 1 in it, the first two elements of the Fibonacci sequence. We have to create these elements \"by hand\", since the iterative part of the sequence requires two previous elements.\n",
"\n",
"We then have a for loop over the list of integers from 2 (the next element of the list) to **n** (the length of the sequence). After the colon, we see a hash tag \"#\", and then a **comment** that if we had set **n** to some number less than 2 we would have a problem. Comments in Python start with #, and are good ways to make notes to yourself or to a user of your code explaining why you did what you did. Better than the comment here would be to test to make sure the value of **n** is valid, and to complain if it isn't; we'll try this later.\n",
"\n",
"In the body of the loop, we append to the list an integer equal to the sum of the two previous elements of the list.\n",
"\n",
"After exiting the loop (ending the indentation) we then print out the whole list. That's it!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Functions\n",
"We might want to use the Fibonacci snippet with different sequence lengths. We could cut an paste the code into another cell, changing the value of **n**, but it's easier and more useful to make a function out of the code. We do this with the **def** statement in Python:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def fibonacci(sequence_length):\n",
" \"Return the Fibonacci sequence of length *sequence_length*\"\n",
" sequence = [0,1]\n",
" if sequence_length < 1:\n",
" print(\"Fibonacci sequence only defined for length 1 or greater\")\n",
" return\n",
" if 0 < sequence_length < 3:\n",
" return sequence[:sequence_length]\n",
" for i in range(2,sequence_length): \n",
" sequence.append(sequence[i-1]+sequence[i-2])\n",
" return sequence"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 63
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now call **fibonacci()** for different sequence_lengths:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fibonacci(2)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 64,
"text": [
"[0, 1]"
]
}
],
"prompt_number": 64
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fibonacci(12)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 65,
"text": [
"[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]"
]
}
],
"prompt_number": 65
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We've introduced a several new features here. First, note that the function itself is defined as a code block (a colon followed by an indented block). This is the standard way that Python delimits things. Next, note that the first line of the function is a single string. This is called a **docstring**, and is a special kind of comment that is often available to people using the function through the python command line:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"help(fibonacci)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on function fibonacci in module __main__:\n",
"\n",
"fibonacci(sequence_length)\n",
" Return the Fibonacci sequence of length *sequence_length*\n",
"\n"
]
}
],
"prompt_number": 66
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you define a docstring for all of your functions, it makes it easier for other people to use them, since they can get help on the arguments and return values of the function.\n",
"\n",
"Next, note that rather than putting a comment in about what input values lead to errors, we have some testing of these values, followed by a warning if the value is invalid, and some conditional code to handle special cases."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Recursion and Factorials\n",
"Functions can also call themselves, something that is often called *recursion*. We're going to experiment with recursion by computing the factorial function. The factorial is defined for a positive integer **n** as\n",
" \n",
"$$ n! = n(n-1)(n-2)\\cdots 1 $$\n",
"\n",
"First, note that we don't need to write a function at all, since this is a function built into the standard math library. Let's use the help function to find out about it:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from math import factorial\n",
"help(factorial)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on built-in function factorial in module math:\n",
"\n",
"factorial(...)\n",
" factorial(x) -> Integral\n",
" \n",
" Find x!. Raise a ValueError if x is negative or non-integral.\n",
"\n"
]
}
],
"prompt_number": 67
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is clearly what we want."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"factorial(20)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 68,
"text": [
"2432902008176640000"
]
}
],
"prompt_number": 68
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However, if we did want to write a function ourselves, we could do recursively by noting that\n",
"\n",
"$$ n! = n(n-1)!$$\n",
"\n",
"The program then looks something like:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def fact(n):\n",
" if n <= 0:\n",
" return 1\n",
" return n*fact(n-1)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 69
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fact(20)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 70,
"text": [
"2432902008176640000"
]
}
],
"prompt_number": 70
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Recursion can be very elegant, and can lead to very simple programs."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Two More Data Structures: Tuples and Dictionaries\n",
"Before we end the Python overview, I wanted to touch on two more data structures that are very useful (and thus very common) in Python programs.\n",
"\n",
"A **tuple** is a sequence object like a list or a string. It's constructed by grouping a sequence of objects together with commas, either without brackets, or with parentheses:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"t = (1,2,'hi',9.0)\n",
"t"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 71,
"text": [
"(1, 2, 'hi', 9.0)"
]
}
],
"prompt_number": 71
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Tuples are like lists, in that you can access the elements using indices:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"t[1]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 72,
"text": [
"2"
]
}
],
"prompt_number": 72
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However, tuples are *immutable*, you can't append to them or change the elements of them:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"t.append(7)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "AttributeError",
"evalue": "'tuple' object has no attribute 'append'",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-73-50c7062b1d5f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m7\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mAttributeError\u001b[0m: 'tuple' object has no attribute 'append'"
]
}
],
"prompt_number": 73
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"t[1]=77"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "'tuple' object does not support item assignment",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-74-03cc8ba9c07d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m77\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
]
}
],
"prompt_number": 74
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Tuples are useful anytime you want to group different pieces of data together in an object, but don't want to create a full-fledged class (see below) for them. For example, let's say you want the Cartesian coordinates of some objects in your program. Tuples are a good way to do this:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"('Bob',0.0,21.0)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 75,
"text": [
"('Bob', 0.0, 21.0)"
]
}
],
"prompt_number": 75
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Again, it's not a necessary distinction, but one way to distinguish tuples and lists is that tuples are a collection of different things, here a name, and x and y coordinates, whereas a list is a collection of similar things, like if we wanted a list of those coordinates:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"positions = [\n",
" ('Bob',0.0,21.0),\n",
" ('Cat',2.5,13.1),\n",
" ('Dog',33.0,1.2)\n",
" ]"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 76
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Tuples can be used when functions return more than one value. Say we wanted to compute the smallest x- and y-coordinates of the above list of objects. We could write:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def minmax(objects):\n",
" minx = 1e20 # These are set to really big numbers\n",
" miny = 1e20\n",
" for obj in objects:\n",
" name,x,y = obj\n",
" if x < minx: \n",
" minx = x\n",
" if y < miny:\n",
" miny = y\n",
" return minx,miny\n",
"\n",
"x,y = minmax(positions)\n",
"print(x,y)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0.0 1.2\n"
]
}
],
"prompt_number": 77
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here we did two things with tuples you haven't seen before. First, we unpacked an object into a set of named variables using *tuple assignment*:\n",
"\n",
" >>> name,x,y = obj\n",
"\n",
"We also returned multiple values (minx,miny), which were then assigned to two other variables (x,y), again by tuple assignment. This makes what would have been complicated code in C++ rather simple.\n",
"\n",
"Tuple assignment is also a convenient way to swap variables:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x,y = 1,2\n",
"y,x = x,y\n",
"x,y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 78,
"text": [
"(2, 1)"
]
}
],
"prompt_number": 78
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Dictionaries** are an object called \"mappings\" or \"associative arrays\" in other languages. Whereas a list associates an integer index with a set of objects:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"mylist = [1,2,9,21]"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 79
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The index in a dictionary is called the *key*, and the corresponding dictionary entry is the *value*. A dictionary can use (almost) anything as the key. Whereas lists are formed with square brackets [], dictionaries use curly brackets {}:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ages = {\"Rick\": 46, \"Bob\": 86, \"Fred\": 21}\n",
"print(\"Rick's age is \",ages[\"Rick\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Rick's age is 46\n"
]
}
],
"prompt_number": 80
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There's also a convenient way to create dictionaries without having to quote the keys."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"dict(Rick=46,Bob=86,Fred=20)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 81,
"text": [
"{'Bob': 86, 'Fred': 20, 'Rick': 46}"
]
}
],
"prompt_number": 81
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The **len()** command works on both tuples and dictionaries:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"len(t)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 82,
"text": [
"4"
]
}
],
"prompt_number": 82
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"len(ages)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 83,
"text": [
"3"
]
}
],
"prompt_number": 83
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting with Matplotlib\n",
"We can generally understand trends in data by using a plotting program to chart it. Python has a wonderful plotting library called [Matplotlib](http://matplotlib.sf.net). The IPython notebook interface we are using for these notes has that functionality built in.\n",
"\n",
"As an example, we have looked at two different functions, the Fibonacci function, and the factorial function, both of which grow faster than polynomially. Which one grows the fastest? Let's plot them. First, let's generate the Fibonacci sequence of length 20:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fibs = fibonacci(10)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 84
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next lets generate the factorials."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"facts = []\n",
"for i in range(10):\n",
" facts.append(factorial(i))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 85
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we use the Matplotlib function **plot** to compare the two."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"figsize(8,6)\n",
"plot(facts,label=\"factorial\")\n",
"plot(fibs,label=\"Fibonacci\")\n",
"xlabel(\"n\")\n",
"legend()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 86,
"text": [
"<matplotlib.legend.Legend at 0x4a24790>"
]
},
{
"output_type": "display_data",
"png": "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\nYvny5SQlJTF9+nRiYmKu+EK+Twa8Ph/ve86ePcucOXP40Y9+xOzZs71dTpcEBwdz77338uGHH3q7\nFI+99957bN++nREjRpCamsrf/vY3Fi5c6O2yPDZ06FAABg8ezP33309RUZGXK/KczWbDZrMxceJE\nAB544AE++ugjL1fVeTt27OB73/segwcP9nYpHvvwww+58847sVgsBAQE8IMf/ID33nvP22V1ysMP\nP8yHH37I22+/jdls5rvf/e5lz+2TAa/Px/sWwzBIT0/H4XCwdOlSb5fTKTU1NTQ0NADQ3NzMrl27\niImJ8XJVnvv1r39NeXk5paWl5ObmMmXKFDZs2ODtsjxy6tQpmpqaADh58iT5+fl98pMm4eHhRERE\ncPjwYcD1/vWYMWO8XFXnbdq0idTUVG+X0SmjRo3igw8+oLm5GcMw2L17d599C+7LL78EoKysjNde\ne+2Kb5n49OfgL8dfPh+fmprK22+/TW1tLREREaxevZqHHnrI22V5bO/evbz88svujzWB6yMp06ZN\n83JlHVddXU1aWhrt7e20t7ezYMECEhISvF1Wl/XFt7OOHz/O/fffD7imuefPn09SUpKXq+qc559/\nnvnz59PS0sKtt97KH//4R2+X1CknT55k9+7dfXY9xPjx41m4cCG33347AwYM4LbbbuMnP/mJt8vq\nlAceeIDa2loCAwPJysoiKCjosuf69M1mREREpHP65BS9iIiIXJkCXkRExA8p4EVERPyQAl5ERMQP\nKeBFxCNHjhxh9OjR/OQnP2Hs2LFMnTqV06dPe7ssEbmIAl5EPPb555/z6KOP8o9//AOz2cz//M//\neLskEbmIAl5EPDZixAjGjRsHwPe+9z2OHDni3YJE5BIKeBHx2DXXXOP+fuDAgbS2tnqxGhH5Ngp4\nERERP6SAFxGPXbwFbl/cElfE32mrWhERET+kEbyIiIgfUsCLiIj4IQW8iIiIH1LAi4iI+CEFvIiI\niB9SwIuIiPih/w8iGJqIcdxOLAAAAABJRU5ErkJggg==\n"
}
],
"prompt_number": 86
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The factorial function grows much faster. In fact, you can't even see the Fibonacci sequence. It's not entirely surprising: a function where we multiply by n each iteration is bound to grow faster than one where we add (roughly) n each iteration.\n",
"\n",
"Let's plot these on a semilog plot so we can see them both a little more clearly:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"semilogy(facts,label=\"factorial\")\n",
"semilogy(fibs,label=\"Fibonacci\")\n",
"xlabel(\"n\")\n",
"legend()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 87,
"text": [
"<matplotlib.legend.Legend at 0x4bf9550>"
]
},
{
"output_type": "display_data",
"png": "iVBORw0KGgoAAAANSUhEUgAAAeYAAAF8CAYAAAAabhjqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3XlYlPX+//EnuKaoiLkBg5gLgnuKFsKRVjXTslQ0O6TY\nZsfOsfJ8s1VoPbadk1n+Ola2SmpZlluFNoYrmWuZoiUyKmVuJCoicP/+uI+TtNjMOHDPDK/HdXHV\njNz3/R4tXn72IMMwDERERMQnBFtdgIiIiPxCwSwiIuJDFMwiIiI+RMEsIiLiQxTMIiIiPkTBLCIi\n4kMUzCIiIj6kprdvaBgGDz74IEePHqVnz56kpqZ6+xEiIiIBy+st5g8//JC9e/dSu3ZtIiMjvX17\nERGRgOb1YM7NzaVPnz4888wzTJ8+3du3FxERCWguBXNaWhrNmzenc+fOFd5fsmQJHTp0oF27dkyZ\nMgWAyMhIQkNDzZsHawhbRETEHUGu7JWdnZ1NSEgIqampbNmyBYCysjJiYmLIysoiIiKC+Ph4MjMz\niY6O5s4776RevXrExsYybty4Sv8QIiIigcKlyV9JSUnk5eVVeC8nJ4e2bdsSHR0NwIgRI5g/fz6T\nJk3ilVde8XadIiIi1YLHs7L37t2LzWZzvo6MjGTt2rUuXRsUFOTpY0VERPySq4c5ejwIfK7hahiG\n339NnjzZ8hr0GQLncwTCZ9Dn8K2vQPgMgfI53OFxMEdEROBwOJyvHQ6HlkeJiIicI4+DuWfPnuzY\nsYO8vDxKSkqYPXs2gwcPdvn69PR07Ha7p48XERHxeXa7nfT0dLeucSmYR44cSUJCArm5udhsNmbO\nnEnNmjWZNm0a/fr1Iy4ujpSUFGJjY11+cHp6OsnJyW4V62v8vX4IjM8AgfE5AuEzgD6HLwmEzwD+\n/TmSk5PdDmaXlkt5W1BQEJMnTyY5Odmvf8NFRETOxm63Y7fbycjIcHms2bJgtuCxIiIBLywsjMOH\nD1tdRrXVuHFjDh069Jv33ck9BbOISADRz1dr/dHvvzt/LtozU0RExIdYFsyalS0iIoHOk1nZ6soW\nEQkg+vlqLXVli4iIX9m+fTvdunWjYcOGTJs2zbI6xo0bx2OPPebS9yYnJ/Pqq69WckW/8Hiv7HN1\neh2zlkuJiFQfTz31FJdddhkbN270+B6jR4/GZrPx6KOPenyP6dOnu/y9QUFBHm9DfXq5lDssHWNW\nKIuIVC+7d+8mLi7O0hrKy8ur7FmebDCirmwREakSl156KXa7nfHjx9OgQQOmTp1K9+7dadSoEVFR\nUWRkZFT4/hUrVpCQkEDjxo2JiorijTfeYMaMGcyaNYunnnqKBg0acM011wDw7bffkpycTOPGjenU\nqRMff/yx8z6jR49m3LhxXHXVVYSEhPD5558zevRoHnroIQAOHz7M1VdfTbNmzQgLC2PQoEHs3bu3\n6n5jfkXBLCIiVWLZsmUkJSXx4osvcvToUbp27crbb79NYWEhCxcuZPr06cyfPx8wW9ZXXXUV//jH\nPzhw4AAbN26kW7du3HLLLYwaNYp7772Xo0ePMn/+fE6dOsWgQYPo378/P/30Ey+88AKjRo0iNzfX\n+ezMzEweeughioqKSExMrNA9bRgGY8eOJT8/n/z8fM477zzGjx9vye8RKJhFRKSKnZ6d3LdvXzp2\n7AhA586dGTFiBMuXLwdg1qxZXHHFFaSkpFCjRg3CwsLo2rXrb+4BsGbNGo4dO8akSZOoWbMml1xy\nCVdffTWZmZnO77n22mu5+OKLAahTp06Fe4SFhTFkyBDq1q1LSEgI999/v7MOK2gds4hINRIU5J2v\nc6vBvMHatWu55JJLaNasGaGhobz88sscPHgQMI8SvuCCC1y63759+7DZbBXea9WqFfv27XM+79e/\nfqbjx49z2223ER0dTaNGjejbty+FhYVeWXZWaadLVQZN/hIRqXqG4Z0vb7jhhhu49tpr2bNnD0eO\nHOH22293hmFUVBTffffd71736xnS4eHhOByOCkG6e/duIiIizvr80/d59tlnyc3NJScnh8LCQpYv\nX45hGF4JZk3+EhERv1FUVETjxo2pXbs2OTk5zJo1y/lrN9xwA1lZWcydO5fS0lIOHjzIpk2bAGje\nvDnff/+983svuugi6tWrx1NPPcWpU6ew2+0sWLCAESNGAPxuwJ4ZvEVFRZx33nk0atSIQ4cO/WYS\n2h/do7IomEVExBIvvfQSDz/8MA0bNuTRRx8lJSXF+WtRUVEsWrSIZ599liZNmtC9e3c2b94MwNix\nY9m6dSuNGzfmuuuuo1atWnz88ccsXryYpk2bMn78eN566y3at28P/P465DPfmzBhAidOnOD8888n\nISGBAQMG/O73VxVtySkiEkD089Vafr0lpyZ/iYhIoNMhFiIi1Zx+vlrLr1vMIiIi8lsKZhERER+i\n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\n"
}
],
"prompt_number": 87
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are many more things you can do with Matplotlib. We'll be looking at some of them in the sections to come. In the meantime, if you want an idea of the different things you can do, look at the Matplotlib [Gallery](http://matplotlib.org/gallery.html). Rob Johansson's IPython notebook [Introduction to Matplotlib](http://nbviewer.ipython.org/urls/raw.github.com/jrjohansson/scientific-python-lectures/master/Lecture-4-Matplotlib.ipynb) is also particularly good."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Conclusion of the Python Overview\n",
"There is, of course, much more to the language than I've covered here. I've tried to keep this brief enough so that you can jump in and start using Python to simplify your life and work. My own experience in learning new things is that the information doesn't \"stick\" unless you try and use it for something in real life.\n",
"\n",
"You will no doubt need to learn more as you go. I've listed several other good references, including the [Python Tutorial](http://docs.python.org/2/tutorial/) and [Learn Python the Hard Way](http://learnpythonthehardway.org/book/). Additionally, now is a good time to start familiarizing yourself with the [Python Documentation](http://docs.python.org/2.7/), and, in particular, the [Python Language Reference](http://docs.python.org/2.7/reference/index.html).\n",
"\n",
"Tim Peters, one of the earliest and most prolific Python contributors, wrote the \"Zen of Python\", which can be accessed via the \"import this\" command:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import this"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"The Zen of Python, by Tim Peters\n",
"\n",
"Beautiful is better than ugly.\n",
"Explicit is better than implicit.\n",
"Simple is better than complex.\n",
"Complex is better than complicated.\n",
"Flat is better than nested.\n",
"Sparse is better than dense.\n",
"Readability counts.\n",
"Special cases aren't special enough to break the rules.\n",
"Although practicality beats purity.\n",
"Errors should never pass silently.\n",
"Unless explicitly silenced.\n",
"In the face of ambiguity, refuse the temptation to guess.\n",
"There should be one-- and preferably only one --obvious way to do it.\n",
"Although that way may not be obvious at first unless you're Dutch.\n",
"Now is better than never.\n",
"Although never is often better than *right* now.\n",
"If the implementation is hard to explain, it's a bad idea.\n",
"If the implementation is easy to explain, it may be a good idea.\n",
"Namespaces are one honking great idea -- let's do more of those!\n"
]
}
],
"prompt_number": 88
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"No matter how experienced a programmer you are, these are words to meditate on."
]
}
],
"metadata": {}
}
]
}
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment