{
 "metadata": {
  "name": "",
  "signature": "sha256:b05a9dca93aaf2f8984b051998cc2dd098000e2319c64c9b2a774fca741c4910"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "<div align=\"center\">\n",
      "<h1>\n",
      "Crash Course on Python (via IPython) and Beginner Visualization and Numerical Computation\n",
      "</h1>\n",
      "<div width=1px height=100px>\n",
      "</div>\n",
      "<h2>\n",
      "Jon Woodring\n",
      "<br>\n",
      "Los Alamos National Laboratory\n",
      "</h2>\n",
      "<h3>\n",
      "The Ohio State University\n",
      "<br>\n",
      "October 10, 2014\n",
      "</h3>\n",
      "</div>"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "# To follow along in IPython #\n",
      "\n",
      "## Step One ##\n",
      "\n",
      "Download this IPython notebook at Github:\n",
      "\n",
      "https://github.com/DataScienceAtScale/python-at-osu-oct-10 *then click on the link in the README*\n",
      "\n",
      "or get it directly via\n",
      "\n",
      "https://raw.githubusercontent.com/DataScienceAtScale/python-at-osu-oct-10/master/Python_at_OSU_Oct_10.ipynb\n",
      "\n",
      "# Optionally follow along without IPython #\n",
      "\n",
      "Use nbviewer to see the static version of the notebook in the web:\n",
      "\n",
      "http://nbviewer.ipython.org/github/DataScienceAtScale/python-at-osu-oct-10/blob/master/Python_at_OSU_Oct_10.ipynb\n",
      "\n",
      "**You can stop here if you are viewing the static web version.**"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "## Step Two ##\n",
      "\n",
      "Download and install Anaconda Python from Continuum Analytics. Use Python 3.4, as there isn't a good reason to use 2.7 as a beginner:\n",
      "\n",
      "http://continuum.io/downloads#py34\n",
      "\n",
      "### Optional Install ###\n",
      "\n",
      "There are other Python options as well, such as *Python(X,Y)*, *WinPython*, *MiniConda* version of *Anaconda*, or using *pip* to install packages with an existing installed version of *Python*. \n",
      "\n",
      "If you are using any of these versions, also make sure that you install:\n",
      "- IPython Notebook (will also get IPython command line as a dependency)\n",
      "- SciPy (will also get NumPy as a dependency)\n",
      "- Pandas\n",
      "- Matplotlib"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "## Step Three ##\n",
      "\n",
      "Launch IPython Notebook in the directory where *Python_at_OSU_Oct_10.ipynb* is located.\n",
      "\n",
      "This will open a webpage for the IPython Notebook interface. From the terminal (for example if you downloaded the notebook in Downloads):\n",
      "\n",
      "```bash\n",
      "$ cd ~/Downloads\n",
      "$ ls Python_at_OSU_Oct_10.ipynb\n",
      "Python_at_OSU_Oct_10.ipynb\n",
      "$ ipython notebook\n",
      "```\n",
      "\n",
      "Alternatively, launch IPython Notebook and copy the notebook file into the directory where ipython was launched:\n",
      "\n",
      "```bash\n",
      "$ cp ~/Downloads/Python_at_OSU_Oct_10.ipynb .\n",
      "$ ipython notebook\n",
      "```"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "### What it looks like if you successfully launched IPython Notebook ###\n",
      "\n",
      "![First page when you open IPython Notebook](front.png)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "## Step Four ##\n",
      "\n",
      "Open the notebook (*Python_at_OSU_Oct_10.ipynb*) from the web interface that was opened in your browser:\n",
      "\n",
      "![After opening the notebook file](opened.png)"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "# 3 Reasons Why I like Python #\n",
      "\n",
      "## Rather than telling you why you should like it, I'm going to tell you why I like it. ##"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "# #1 My 881 project written in Python (taken with with Professor Dey) still works #\n",
      "## I haven't touched it in 10+ years and I just ran it last Friday to see if it worked ##\n",
      "\n",
      "![Curves and subdivision surfaces in Python](881.png)\n",
      "\n",
      "# Yep! Still works! #"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "# #2 import antigravity #\n",
      "\n",
      "![I wrote 20 short programs in Python yesterday.  It was wonderful.  Perl, I'm leaving you.](http://imgs.xkcd.com/comics/python.png)\n",
      "\n",
      "## and a million other things: numerics, graphics, web, GPU, distributed, GUIs, databases, analytics, etc.\n",
      "\n",
      "### The things that Python isn't good at (yet): compilation and shared-memory threading ###"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "# #3 IPython + Matplotlib + Numpy + SciPy + SQLite = Amazing #\n",
      "\n",
      "- ## Everything in this tutorial was created with these Python tools ##\n",
      "- ## An honorable mention goes to Cython, which makes it really easy to call C code directly from Python ##\n",
      "\n",
      "# Plus, the language is fun. It is so easy to do anything. #\n",
      "\n",
      "- ## I have written volume renderers, high-dimensional visualizations, analysis tools, web servers, benchmarks, parallel processing, data manipulation, demonstrations, etc. all in Python ##\n",
      "- ## I use Python because premature optimization is the downfall of coding productivity. There is no good reason to start with C/C++ when 95% of the time in Visualization and Analysis our bottleneck is I/O. If you need to make it go fast, find your bottlenecks, and *optimize LATER not at the start*. ##"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# So let's get into it\n",
      "\n",
      "print('Hello world!')"
     ],
     "language": "python",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "Hello world!\n"
       ]
      }
     ],
     "prompt_number": 1
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# An Interactive Demo of IPython Notebook - Shown by Jon #\n",
      "\n",
      "# To execute IPython Cells, press *Ctrl-Enter* or the play button on the toolbar #\n",
      "\n",
      "# The static view has the output cached already #"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "source": [
      "# Python #\n",
      "\n",
      "- A dynamically typed language (methods and functions are checked at run-time)\n",
      "- Whitespace is meaningful for blocks (no semi-colons/terminators)\n",
      "- Syntax is C-like (procedural, Algol-like)\n",
      "- Built-in immutable data types: integers, floating point, strings, tuples, etc.\n",
      "- Built-in mutable data structures: lists, associative maps (dicts/hashes), sets, etc.\n",
      "- Automatic memory management (reference counting)\n",
      "- Exception handling (try/except)\n",
      "- Functions are first-class (they can be passed around as arguments)\n",
      "- Object-oriented paradigms can be used (classes)\n",
      "- A huge standard library\n",
      "- CPython is the standard implementation, which is interpreted (there are efforts to make JIT compilers, such as *pypy* and *Numba*)\n",
      "- Bind to C for speed (Python is an excellent \"glue\" language)\n"
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# assignment & print function\n",
      "\n",
      "x = 0 # you don't have to declare x first\n",
      "print(x) # calling built-in function\n",
      "\n",
      "y = 1.0 # just assign a literal to a name\n",
      "print(y) # calling looks just like C and other Algol-languages\n",
      "\n",
      "z = 'foo' # a string with quotes\n",
      "print(z) # no semi-colons or other terminators\n",
      "\n",
      "w = \"bar\" # another string with double quotes (either works)\n",
      "print(w)"
     ],
     "language": "python",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "0\n",
        "1.0\n",
        "foo\n",
        "bar\n"
       ]
      }
     ],
     "prompt_number": 2
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# more assignment & expressions\n",
      "\n",
      "x = 1\n",
      "y = 2\n",
      "z = 3\n",
      "r = 'one'\n",
      "s = 'two'\n",
      "t = 'three'\n",
      "f = 1.0\n",
      "\n",
      "a = x * y + z # expressions look like most other infix notation\n",
      "print(a)\n",
      "\n",
      "print(r + s + t) # concatenating strings & expression \n",
      "                 # in a function argument\n",
      "\n",
      "b, c, d = x + f, 4 * f, y ** z # multiple assigments on one line\n",
      "print(b, c, d) # adding numeric types casts integer to float\n",
      "\n",
      "print(x + r) # but this doesn't work \n",
      "             # (won't cast a numeric to a string, unlike Javascript)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "5\n",
        "onetwothree\n",
        "2.0 4.0 8\n"
       ]
      },
      {
       "ename": "TypeError",
       "evalue": "unsupported operand type(s) for +: 'int' and 'str'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-3-1adb0bd1160d>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     18\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mb\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mc\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0md\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# adding numeric types casts integer to float\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     19\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 20\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mr\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# but this doesn't work\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     21\u001b[0m              \u001b[1;31m# (won't cast a numeric to a string, unlike Javascript)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'"
       ]
      }
     ],
     "prompt_number": 3
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# conversions and types\n",
      "\n",
      "x = '1.01'\n",
      "\n",
      "print(x, type(x)) # type is another built-in function\n",
      "x = float(x) # x is now a float\n",
      "print(x, type(x)) # print can take multiple arguments\n",
      "x = int(x)\n",
      "print(x, type(x)) # now it's an integer\n",
      "x = str(x)\n",
      "print(x, type(x))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1.01 <class 'str'>\n",
        "1.01 <class 'float'>\n",
        "1 <class 'int'>\n",
        "1 <class 'str'>\n"
       ]
      }
     ],
     "prompt_number": 4
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# lists (vectors, really)\n",
      "\n",
      "x = [1, 2, 3, 4, 5] # a list of integers\n",
      "print(x)\n",
      "\n",
      "y = [1.0, 2.0, 3.0, 4.0, 5.0] # a list of floating point\n",
      "print(y)\n",
      "\n",
      "z = ['a', 'b', 'c', 'd', 'e'] # a list of strings\n",
      "print(z)\n",
      "\n",
      "w = [1, 'two', 3.0, \"four\", print, 'last'] # can we mix them?\n",
      "print(w) # yes, we can"
     ],
     "language": "python",
     "metadata": {
      "slideshow": {
       "slide_type": "slide"
      }
     },
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[1, 2, 3, 4, 5]\n",
        "[1.0, 2.0, 3.0, 4.0, 5.0]\n",
        "['a', 'b', 'c', 'd', 'e']\n",
        "[1, 'two', 3.0, 'four', <built-in function print>, 'last']\n"
       ]
      }
     ],
     "prompt_number": 5
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# accessing lists\n",
      "\n",
      "w = [1, 'two', 3.0, \"four\", print, 'last'] \n",
      "print(w)\n",
      "\n",
      "# accessing is array notation\n",
      "# a Python list is like a \"vector\" in C++\n",
      "# random access, reverse is constant time, etc.\n",
      "# i.e., deleting from the front is linear time\n",
      "print(w[0]) # first item\n",
      "print(w[1]) # second item\n",
      "print(w[len(w)-1]) # last item, len is a built-in function\n",
      "print(w[-1]) # this is the last item, too\n",
      "print(w[-2]) # second to last\n",
      "\n",
      "w[0] = w[-1] # let's copy the last item to the first\n",
      "print(w[0])"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[1, 'two', 3.0, 'four', <built-in function print>, 'last']\n",
        "1\n",
        "two\n",
        "last\n",
        "last\n",
        "<built-in function print>\n",
        "last\n"
       ]
      }
     ],
     "prompt_number": 6
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# list slices\n",
      "\n",
      "w = [1, 2, 3, 4, 5]\n",
      "\n",
      "# slices - similar to Matlab and Fortran\n",
      "print(w[2:]) # everything from 2 onwards\n",
      "print(w[:2]) # right hand index is exclusive (Python uses 0-indexing)\n",
      "print(w[:2] + w[2:]) # list concatenation\n",
      "\n",
      "# you can do subranges\n",
      "print(w[1:3])\n",
      "\n",
      "# you can do skips\n",
      "print(w[::2])\n",
      "\n",
      "# even in reverse\n",
      "print(w[::-1])\n",
      "\n",
      "# you can combine them all together\n",
      "print(w[3:0:-2]) # notice I had to do 3 to 0 by -2 to go in reverse"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[3, 4, 5]\n",
        "[1, 2]\n",
        "[1, 2, 3, 4, 5]\n",
        "[2, 3]\n",
        "[1, 3, 5]\n",
        "[5, 4, 3, 2, 1]\n",
        "[4, 2]\n"
       ]
      }
     ],
     "prompt_number": 7
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "w = [1, 2, 3, 4, 5]\n",
      "\n",
      "# a slice is a copy\n",
      "v = w[::-1]\n",
      "v[0] = 'first'\n",
      "print(v, w)\n",
      "\n",
      "# such that : means copy\n",
      "u = v[:]\n",
      "u[-1] = 'last'\n",
      "print(u, v)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "['first', 4, 3, 2, 1] [1, 2, 3, 4, 5]\n",
        "['first', 4, 3, 2, 'last'] ['first', 4, 3, 2, 1]\n"
       ]
      }
     ],
     "prompt_number": 8
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# lists of lists\n",
      "\n",
      "x = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # what about lists of lists?\n",
      "print(x)\n",
      "print(x[0][0]) # double accessors to get the inner list items\n",
      "print(x[-1][-1])\n",
      "print(x[1:][1:]) # except this is probably not what you are expecting\n",
      "\n",
      "y = [['a', 1, 2], [3.0], [4 + 3, ['seven', ['eight']], 'nine']]\n",
      "print(y) # nothing stopping arbitrary list nesting\n",
      "print(y[2][1][1][0]) # anything can go in a list"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[[1, 2, 3], [4, 5, 6], [7, 8, 9]]\n",
        "1\n",
        "9\n",
        "[[7, 8, 9]]\n",
        "[['a', 1, 2], [3.0], [7, ['seven', ['eight']], 'nine']]\n",
        "eight\n"
       ]
      }
     ],
     "prompt_number": 9
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# list iteration\n",
      "\n",
      "z = [1, 2, 3]\n",
      "n = []\n",
      "for i in z: # iterating over a list\n",
      "    n.append(i + 1) # append is a method on a list \n",
      "                    # that modifies it in place (it returns None)\n",
      "print(n, z)\n",
      "\n",
      "w = [[1, 2], [3, 4], [5, 6]]\n",
      "s = ''\n",
      "for i in w: # iterate over a list\n",
      "    for j in i: # iterate over another list\n",
      "        s = s + str(j)\n",
      "print(s)\n",
      "        \n",
      "q = []\n",
      "# iterate over two lists in tandem with zip\n",
      "for i, j in zip(z, n):\n",
      "    print('i:', i, 'j:', j, 'i+j:', i + j)\n",
      "    q.append(i + j)\n",
      "print(q)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[2, 3, 4] [1, 2, 3]\n",
        "123456\n",
        "i: 1 j: 2 i+j: 3\n",
        "i: 2 j: 3 i+j: 5\n",
        "i: 3 j: 4 i+j: 7\n",
        "[3, 5, 7]\n"
       ]
      }
     ],
     "prompt_number": 10
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# if you want to modify a list in place, use the accessors\n",
      "# i.e., like how you would in C\n",
      "z = [1, 2, 3, 4, 5]\n",
      "for i in range(0, len(z)): # range is a special \"list\" \n",
      "                           # (iterator, actually) \n",
      "                           # that gives you integers\n",
      "    z[i] = z[i] + 1\n",
      "print(z) # basically, that was a for loop from 0 to 5 (exclusive)\n",
      "\n",
      "z = [1, 2, 3, 4, 5]\n",
      "for i in z: # this does nothing because i is a copy of the item in z\n",
      "    i = i + 1\n",
      "print(z)\n",
      "\n",
      "# DON'T DO THIS: IT WILL NEVER RETURN\n",
      "# for i in z: # iterating over a list\n",
      "#     z.append(i + 1) # but you just added to the end of z, \n",
      "#                     # so, z keeps growing, such that \n",
      "#                     # you will never hit the end of z\n",
      "\n",
      "# basically, don't try to modify the list while iterating over it\n",
      "# lots of \"bad\" things can happen"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[2, 3, 4, 5, 6]\n",
        "[1, 2, 3, 4, 5]\n"
       ]
      }
     ],
     "prompt_number": 11
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# tuples - basically, immutable lists\n",
      "# there are also sets and frozensets (mutable and immutable sets)\n",
      "empty = ()\n",
      "print(empty)\n",
      "print(len(empty))\n",
      "\n",
      "a = (1, 2, 3)\n",
      "print(a)\n",
      "\n",
      "print(a[0], a[-1], a[1:])\n",
      "\n",
      "for i in a:\n",
      "    print(i + 1)\n",
      "\n",
      "a[0] = 'a' # this is going to fail, because tuples are immutable\n",
      "\n",
      "# strings are immutable, too, as with all other basic data types,\n",
      "# while containers are mutable (except tuples and frozensets)\n",
      "s = 'a string'\n",
      "s[0] = 'a' # this will fail too"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "()\n",
        "0\n",
        "(1, 2, 3)\n",
        "1 3 (2, 3)\n",
        "2\n",
        "3\n",
        "4\n"
       ]
      },
      {
       "ename": "TypeError",
       "evalue": "'tuple' object does not support item assignment",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-13-3f201cd96ca7>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     13\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mi\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     14\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 15\u001b[1;33m \u001b[0ma\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'a'\u001b[0m \u001b[1;31m# this is going to fail, because tuples are immutable\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     16\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[1;31m# strings are immutable, too, as with all other basic data types,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
       ]
      }
     ],
     "prompt_number": 13
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# dicts : maps, hashes, associative arrays\n",
      "# lists, dicts, and tuples are all accessed in\n",
      "# similar ways\n",
      "\n",
      "empty = {}\n",
      "print(empty)\n",
      "print(empty.keys()) # dicts have keys\n",
      "print(empty.values()) # and values (it's a map)\n",
      "\n",
      "a = {'one': 1, 2: 'two', 'print': print} # we can store all \n",
      "                                         # sorts of things in a dict, \n",
      "                                         # just like a list and tuple\n",
      "print(a)\n",
      "print(a['one']) # and we can use all sorts of keys\n",
      "print(a[2])\n",
      "print(a['print']) # even functions can be fetched\n",
      "a['print'](\"hi there, I'm a function in a dict!\") # call it\n",
      "\n",
      "for k in a:\n",
      "    print('key:', k, 'value:', a[k])\n",
      "    \n",
      "print('a key' in a) # boolean is a built-in type: True or False\n",
      "a['a key'] # this is going to fail"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "{}\n",
        "dict_keys([])\n",
        "dict_values([])\n",
        "{'print': <built-in function print>, 2: 'two', 'one': 1}\n",
        "1\n",
        "two\n",
        "<built-in function print>\n",
        "hi there, I'm a function in a dict!\n",
        "key: print value: <built-in function print>\n",
        "key: 2 value: two\n",
        "key: one value: 1\n",
        "False\n"
       ]
      },
      {
       "ename": "KeyError",
       "evalue": "'a key'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-14-2361f8fa98e9>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     19\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     20\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'a key'\u001b[0m \u001b[1;32min\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# boolean is a built-in type: True or False\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 21\u001b[1;33m \u001b[0ma\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'a key'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;31m# this is going to fail\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;31mKeyError\u001b[0m: 'a key'"
       ]
      }
     ],
     "prompt_number": 14
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# simple boolean expressions\n",
      "\n",
      "s_one = '1'\n",
      "i_one = 1\n",
      "f_one = 1.0\n",
      "i_two = 2\n",
      "i_other_one = 1\n",
      "\n",
      "print('\"1\" = 1?', s_one == i_one) # strings can't equal numerics\n",
      "print('1 < 2?', i_one < i_two)\n",
      "print('1.0 > 2?', f_one > i_two)\n",
      "print('1 = 1.0?', i_one == f_one)\n",
      "print('\"1\" = str(1)?', s_one == str(i_one)) \n",
      "print('1 =/= 1?', i_one != i_other_one)  "
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\"1\" = 1? False\n",
        "1 < 2? True\n",
        "1.0 > 2? False\n",
        "1 = 1.0? True\n",
        "\"1\" = str(1)? True\n",
        "1 =/= 1? False\n"
       ]
      }
     ],
     "prompt_number": 15
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# is vs. equality\n",
      "\n",
      "a = [1, 2, 3, 4, 5]\n",
      "b = [1, 2, 3, 4, 5]\n",
      "c = [1, 2, 3, 4]\n",
      "d = [2, 2, 3, 4, 5]\n",
      "\n",
      "print(a == a)\n",
      "print(a == b) # equality works for lists and containers\n",
      "print(a == c)\n",
      "print(a == d)\n",
      "\n",
      "# but what if you want to know about references?\n",
      "print(a is a)\n",
      "print(a is b) # False, they are not the same reference\n",
      "\n",
      "# x is y -> id(x) == id(y)\n",
      "print(id(a) == id(a))\n",
      "print(id(a) == id(b)) # this is equivalent to 'a is b'"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "True\n",
        "True\n",
        "False\n",
        "False\n",
        "True\n",
        "False\n",
        "True\n",
        "False\n"
       ]
      }
     ],
     "prompt_number": 16
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# copies vs. references of lists\n",
      "a = ['A']\n",
      "b = ['B']\n",
      "c = ['C']\n",
      "d = [a, b, c] # list of lists\n",
      "print('d:', d)\n",
      "print('a:', a, 'b:', b, 'c:', c)\n",
      "\n",
      "d[0] = d[-1] # list c isn't copied\n",
      "print('d:', d) # list c is in both places\n",
      "print('a:', a, 'b:', b, 'c:', c) # a is still the same, \n",
      "                                 # and d[0] and d[-1] reference c\n",
      "\n",
      "temp = a[0]\n",
      "a[0] = b[0] # this string will be copied\n",
      "b[0] = temp\n",
      "print('d:', d) # all the built-in types are copied \n",
      "               # (i.e., int, float, string, etc.)\n",
      "print('a:', a, 'b:', b, 'c:', c) # but built-in data structures \n",
      "                                 # (i.e., lists, classes, maps, etc.)\n",
      "                                 # are referenced"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "d: [['A'], ['B'], ['C']]\n",
        "a: ['A'] b: ['B'] c: ['C']\n",
        "d: [['C'], ['B'], ['C']]\n",
        "a: ['A'] b: ['B'] c: ['C']\n",
        "d: [['C'], ['A'], ['C']]\n",
        "a: ['B'] b: ['A'] c: ['C']\n"
       ]
      }
     ],
     "prompt_number": 17
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# immutability and is\n",
      "\n",
      "# what if you try 'is' on two numbers?\n",
      "a = 1\n",
      "b = 1\n",
      "print(a is b) # True? what's going on here?\n",
      "print(id(a))\n",
      "print(id(b)) # they point to the same thing\n",
      "\n",
      "# basic types, such as string, integers, floats, get reused \"interned\"\n",
      "# and are actually immutable - the other types (lists, classes, maps) are mutable\n",
      "\n",
      "# so, when you call a function, you are always passing by reference\n",
      "def is_it(x, y):\n",
      "    z = a # get a new reference to x\n",
      "    print(id(x), id(y), id(z))\n",
      "\n",
      "is_it(a, b)\n",
      "is_it([1, 2, 3], [1, 2, 3]) # difference references\n",
      "\n",
      "# but only to a certain point\n",
      "a = 100000000 # they will have different ids\n",
      "b = 100000000\n",
      "print(a is b)\n",
      "print(a == b) # all of this is done because Python uses a lot of hashing\n",
      "              # for optimization - because you can hash immutable data\n",
      "    \n",
      "# for example, you can only use immutable data for keys in dicts        \n",
      "a = {}\n",
      "a[[1, 2, 3]] = b # a list is unhashable"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "True\n",
        "140368470091648\n",
        "140368470091648\n",
        "140368470091648 140368470091648 140368470091648\n",
        "140368256473544 140368256473800 140368470091648\n",
        "False\n",
        "True\n"
       ]
      },
      {
       "ename": "TypeError",
       "evalue": "unhashable type: 'list'",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-18-c7ade888dec8>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     28\u001b[0m \u001b[1;31m# for example, you can only use immutable data for keys in dicts\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     29\u001b[0m \u001b[0ma\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 30\u001b[1;33m \u001b[0ma\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mb\u001b[0m \u001b[1;31m# a list is unhashable\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;31mTypeError\u001b[0m: unhashable type: 'list'"
       ]
      }
     ],
     "prompt_number": 18
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# compound boolean expressions\n",
      "\n",
      "print(not False)\n",
      "print(False or True)\n",
      "print(True and False)\n",
      "print((False and True) or not True)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "True\n",
        "True\n",
        "False\n",
        "False\n"
       ]
      }
     ],
     "prompt_number": 19
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# if-then-else & block indentation\n",
      "\n",
      "x = 1\n",
      "y = 2\n",
      "z = 3\n",
      "\n",
      "# see how blocks line up due to spacing?\n",
      "# PEP 8 says the preferred tab stop is 4 spaces (don't use tabs)\n",
      "# I prefer 2, personally\n",
      "if x < 1 or False:\n",
      "    print('not here')\n",
      "elif y < 2 and True:\n",
      "    print('not here either')\n",
      "elif z > 0:\n",
      "    print('we got here')\n",
      "    if not x != y:\n",
      "        print('nope')\n",
      "    elif z == 3:\n",
      "        print('here too')\n",
      "        if z < y or y < x:\n",
      "            print('not here either')\n",
      "        else:\n",
      "            print('we got all the way here')\n",
      "            while z > x:\n",
      "                z = z - 1\n",
      "                if y > x:\n",
      "                    y = y - x\n",
      "                else:\n",
      "                    y = y - 2\n",
      "            while z >= y:\n",
      "                z = z - 1\n",
      "                if x > 0:\n",
      "                    x = x + 1\n",
      "    else:\n",
      "        print('nada')\n",
      "else:\n",
      "    print('not gonna get here')\n",
      "print(x, y, z)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "we got here\n",
        "here too\n",
        "we got all the way here\n",
        "4 -1 -2\n"
       ]
      }
     ],
     "prompt_number": 20
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# 0-argument functions and returning\n",
      "\n",
      "def nop(): # no argument list\n",
      "    pass # do nothing\n",
      "\n",
      "print(nop) # nop is a function\n",
      "print(nop()) # call it, functions return None \n",
      "             # if there isn't an explicit return\n",
      "\n",
      "def one(): # no argument list\n",
      "    return 1\n",
      "\n",
      "print(one())\n",
      "\n",
      "# functions are first-class\n",
      "temp = nop\n",
      "nop = one\n",
      "one = temp\n",
      "\n",
      "print(nop(), one())"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "<function nop at 0x7faa0815cbf8>\n",
        "None\n",
        "1\n",
        "1 None\n"
       ]
      }
     ],
     "prompt_number": 21
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# arguments to functions and returning values\n",
      "\n",
      "def xyz(x): # one argument, no types needed\n",
      "    return x, x # this means it is returning a tuple\n",
      "\n",
      "print(xyz(1)) \n",
      "\n",
      "def uvw(u, v): # two arguments\n",
      "    return (u, v) # we can do it explicitly, too\n",
      "\n",
      "print(uvw(1, 2))\n",
      "\n",
      "def abc(a, b, c):\n",
      "    return [a, b, c] # we can return lists\n",
      "\n",
      "print(abc(1, 2, 3))\n",
      "\n",
      "# btw, these two are equivalent\n",
      "i, j = (3, 4)\n",
      "print(i, j)\n",
      "(i, j) = 3, 4\n",
      "print(i, j)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "(1, 1)\n",
        "(1, 2)\n",
        "[1, 2, 3]\n",
        "3 4\n",
        "3 4\n"
       ]
      }
     ],
     "prompt_number": 23
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# recursion works just fine\n",
      "\n",
      "def ye_old_fib(n):\n",
      "    if n < 2:\n",
      "        return 1\n",
      "    else:\n",
      "        return ye_old_fib(n - 1) + ye_old_fib(n - 2)\n",
      "    \n",
      "fibs = []\n",
      "for i in range(0, 10):\n",
      "    fibs = fibs + [ye_old_fib(i)] # append done another way\n",
      "print(fibs)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n"
       ]
      }
     ],
     "prompt_number": 24
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# named arguments and default values\n",
      "\n",
      "def plus_one(x):\n",
      "    return x + 1\n",
      "\n",
      "def plus_two(x):\n",
      "    return x + 2\n",
      "\n",
      "# argument v and f have default values\n",
      "def func_caller(v = 1, f = plus_one): \n",
      "    return f(v) # we can call arguments that are functions\n",
      "\n",
      "print(func_caller()) # we don't have to pass an argument for v and f\n",
      "print(func_caller(2)) # they are applied left to right\n",
      "print(func_caller(2, plus_two))\n",
      "print(func_caller(f=plus_two)) # we can bypass the order by naming them"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "2\n",
        "3\n",
        "4\n",
        "3\n"
       ]
      }
     ],
     "prompt_number": 25
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# scope is function level NOT block level\n",
      "# Local Function -> Outer Function -> Global -> Python Defined\n",
      "\n",
      "# assignment determines scope\n",
      "# you can think of '=' as declaration in Python\n",
      "value = 1 # global\n",
      "\n",
      "def modify_value(): \n",
      "    value = 2 # local scope for value\n",
      "    \n",
      "    def modify_modify_value():\n",
      "        value = 3 # inner scope\n",
      "        \n",
      "        if True:\n",
      "            value = 4 # we look at the function scope\n",
      "        \n",
      "        print(value) # this will be 4, not 3\n",
      "    \n",
      "    modify_modify_value()\n",
      "    print(value) # 2 not 3 or 4\n",
      "\n",
      "print(value)\n",
      "modify_value()\n",
      "print(value)\n",
      "del value # remove a name from scope and reclaim memory\n",
      "print(value) # this is going to be undefined"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1\n",
        "4\n",
        "2\n",
        "1\n"
       ]
      },
      {
       "ename": "NameError",
       "evalue": "name 'value' is not defined",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-26-88dc96fa7cc1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     24\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     25\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mvalue\u001b[0m \u001b[1;31m# remove a name from scope and reclaim memory\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 26\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# this is going to be undefined\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;31mNameError\u001b[0m: name 'value' is not defined"
       ]
      }
     ],
     "prompt_number": 26
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# assignment establishes scope\n",
      "\n",
      "if True:\n",
      "    some_thing = 1 # it gets \"declared\" here, but not \"lifted\"\n",
      "print(some_thing)\n",
      "\n",
      "print(not_lifted + 1) # not_lifted is not in scope yet\n",
      "if True:\n",
      "    not_lifted = 1"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "1\n"
       ]
      },
      {
       "ename": "NameError",
       "evalue": "name 'not_lifted' is not defined",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-27-2c757dd657b1>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0msome_thing\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnot_lifted\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# not_lifted is not in scope yet\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      8\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m     \u001b[0mnot_lifted\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;31mNameError\u001b[0m: name 'not_lifted' is not defined"
       ]
      }
     ],
     "prompt_number": 27
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# more scope examples\n",
      "\n",
      "foo = ['bar'] # global scope\n",
      "\n",
      "def pretend_modify():\n",
      "    foo = ['nope'] # new scope established\n",
      "\n",
      "def actually_modify():\n",
      "    foo.append('yep') # we use outer scope\n",
      "                      # because it isn't assignment\n",
      "        \n",
      "def gonna_fail():\n",
      "    foo.append('whoops') # this will break because foo isn't in scope\n",
      "    foo = ['broked']     # because this assignment created a new scope\n",
      "    \n",
      "print(foo)\n",
      "pretend_modify()\n",
      "print(foo)\n",
      "actually_modify()\n",
      "print(foo)\n",
      "gonna_fail()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "['bar']\n",
        "['bar']\n",
        "['bar', 'yep']\n"
       ]
      },
      {
       "ename": "UnboundLocalError",
       "evalue": "local variable 'foo' referenced before assignment",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mUnboundLocalError\u001b[0m                         Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-28-4c3c00ae6438>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     19\u001b[0m \u001b[0mactually_modify\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     20\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfoo\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 21\u001b[1;33m \u001b[0mgonna_fail\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;32m<ipython-input-28-4c3c00ae6438>\u001b[0m in \u001b[0;36mgonna_fail\u001b[1;34m()\u001b[0m\n\u001b[0;32m     11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mgonna_fail\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m     \u001b[0mfoo\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'whoops'\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# this will break because foo isn't in scope\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     14\u001b[0m     \u001b[0mfoo\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;34m'broked'\u001b[0m\u001b[1;33m]\u001b[0m     \u001b[1;31m# because this assignment created a new scope\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
        "\u001b[1;31mUnboundLocalError\u001b[0m: local variable 'foo' referenced before assignment"
       ]
      }
     ],
     "prompt_number": 28
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# files\n",
      "\n",
      "f = open('foo.txt', 'w')\n",
      "f.write('hi there!\\n')\n",
      "f.close()\n",
      "\n",
      "g = open('foo.txt', 'r')\n",
      "s = g.read(10)\n",
      "g.close()\n",
      "\n",
      "print(s)\n",
      "\n",
      "# the struct module and ctypes are useful for mass binary\n",
      "# conversion of data, as well as the numpy from_file/to_file\n",
      "# operations\n",
      "f = open('bar.bin', 'wb')\n",
      "f.write((10).to_bytes(1, 'little')) # I'd normally use struct\n",
      "f.close()\n",
      "\n",
      "g = open('bar.bin', 'rb')\n",
      "i = int.from_bytes(g.read(1), 'little') # Or numpy.fromfile\n",
      "g.close()\n",
      "\n",
      "print(i)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "hi there!\n",
        "\n",
        "10\n"
       ]
      }
     ],
     "prompt_number": 29
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# modules, help, and dir\n",
      "\n",
      "l = [1, 2, 3, 4, 5]\n",
      "print(dir(l)) # what's in l?\n",
      "\n",
      "import sys # sys module (a library, basically)\n",
      "print(dir(sys)) # what's in the sys module?\n",
      "\n",
      "from os import * # import everything in os into this namespace\n",
      "print(dir()) # what's in the global namespace, now?\n",
      "\n",
      "print(help(sys)) # get module help\n",
      "\n",
      "print(help(sys.exit)) # get help on sys.exit"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']\n",
        "['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe', '_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'ps3', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions']\n",
        "['In', 'Out', 'P_NOWAIT', 'P_NOWAITO', 'P_WAIT', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', '_', '__', '___', '__builtin__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_dh', '_exit', '_i', '_i1', '_i10', '_i11', '_i12', '_i13', '_i14', '_i15', '_i16', '_i17', '_i18', '_i19', '_i2', '_i20', '_i21', '_i22', '_i23', '_i24', '_i25', '_i26', '_i27', '_i28', '_i29', '_i3', '_i30', '_i4', '_i5', '_i6', '_i7', '_i8', '_i9', '_ih', '_ii', '_iii', '_oh', '_sh', 'a', 'abc', 'actually_modify', 'altsep', 'b', 'c', 'curdir', 'd', 'defpath', 'devnull', 'empty', 'environb', 'execl', 'execle', 'execlp', 'execlpe', 'execvp', 'execvpe', 'exit', 'extsep', 'f', 'f_one', 'fdopen', 'fibs', 'foo', 'fsdecode', 'fsencode', 'func_caller', 'fwalk', 'g', 'get_exec_path', 'get_ipython', 'getenv', 'getenvb', 'gonna_fail', 'i', 'i_one', 'i_other_one', 'i_two', 'is_it', 'j', 'k', 'l', 'linesep', 'makedirs', 'modify_value', 'n', 'name', 'nop', 'one', 'pardir', 'path', 'pathsep', 'plus_one', 'plus_two', 'popen', 'pretend_modify', 'putenv', 'q', 'quit', 'r', 'removedirs', 'renames', 's', 's_one', 'sep', 'some_thing', 'spawnl', 'spawnle', 'spawnlp', 'spawnlpe', 'spawnv', 'spawnve', 'spawnvp', 'spawnvpe', 'supports_bytes_environ', 'sys', 't', 'temp', 'u', 'unsetenv', 'uvw', 'v', 'w', 'walk', 'x', 'xyz', 'y', 'ye_old_fib', 'z']\n",
        "Help on built-in module sys:\n",
        "\n",
        "NAME\n",
        "    sys\n",
        "\n",
        "MODULE REFERENCE\n",
        "    http://docs.python.org/3.4/library/sys\n",
        "    \n",
        "    The following documentation is automatically generated from the Python\n",
        "    source files.  It may be incomplete, incorrect or include features that\n",
        "    are considered implementation detail and may vary between Python\n",
        "    implementations.  When in doubt, consult the module reference at the\n",
        "    location listed above.\n",
        "\n",
        "DESCRIPTION\n",
        "    This module provides access to some objects used or maintained by the\n",
        "    interpreter and to functions that interact strongly with the interpreter.\n",
        "    \n",
        "    Dynamic objects:\n",
        "    \n",
        "    argv -- command line arguments; argv[0] is the script pathname if known\n",
        "    path -- module search path; path[0] is the script directory, else ''\n",
        "    modules -- dictionary of loaded modules\n",
        "    \n",
        "    displayhook -- called to show results in an interactive session\n",
        "    excepthook -- called to handle any uncaught exception other than SystemExit\n",
        "      To customize printing in an interactive session or to install a custom\n",
        "      top-level exception handler, assign other functions to replace these.\n",
        "    \n",
        "    stdin -- standard input file object; used by input()\n",
        "    stdout -- standard output file object; used by print()\n",
        "    stderr -- standard error object; used for error messages\n",
        "      By assigning other file objects (or objects that behave like files)\n",
        "      to these, it is possible to redirect all of the interpreter's I/O.\n",
        "    \n",
        "    last_type -- type of last uncaught exception\n",
        "    last_value -- value of last uncaught exception\n",
        "    last_traceback -- traceback of last uncaught exception\n",
        "      These three are only available in an interactive session after a\n",
        "      traceback has been printed.\n",
        "    \n",
        "    Static objects:\n",
        "    \n",
        "    builtin_module_names -- tuple of module names built into this interpreter\n",
        "    copyright -- copyright notice pertaining to this interpreter\n",
        "    exec_prefix -- prefix used to find the machine-specific Python library\n",
        "    executable -- absolute path of the executable binary of the Python interpreter\n",
        "    float_info -- a struct sequence with information about the float implementation.\n",
        "    float_repr_style -- string indicating the style of repr() output for floats\n",
        "    hash_info -- a struct sequence with information about the hash algorithm.\n",
        "    hexversion -- version information encoded as a single integer\n",
        "    implementation -- Python implementation information.\n",
        "    int_info -- a struct sequence with information about the int implementation.\n",
        "    maxsize -- the largest supported length of containers.\n",
        "    maxunicode -- the value of the largest Unicode codepoint\n",
        "    platform -- platform identifier\n",
        "    prefix -- prefix used to find the Python library\n",
        "    thread_info -- a struct sequence with information about the thread implementation.\n",
        "    version -- the version of this interpreter as a string\n",
        "    version_info -- version information as a named tuple\n",
        "    __stdin__ -- the original stdin; don't touch!\n",
        "    __stdout__ -- the original stdout; don't touch!\n",
        "    __stderr__ -- the original stderr; don't touch!\n",
        "    __displayhook__ -- the original displayhook; don't touch!\n",
        "    __excepthook__ -- the original excepthook; don't touch!\n",
        "    \n",
        "    Functions:\n",
        "    \n",
        "    displayhook() -- print an object to the screen, and save it in builtins._\n",
        "    excepthook() -- print an exception and its traceback to sys.stderr\n",
        "    exc_info() -- return thread-safe information about the current exception\n",
        "    exit() -- exit the interpreter by raising SystemExit\n",
        "    getdlopenflags() -- returns flags to be used for dlopen() calls\n",
        "    getprofile() -- get the global profiling function\n",
        "    getrefcount() -- return the reference count for an object (plus one :-)\n",
        "    getrecursionlimit() -- return the max recursion depth for the interpreter\n",
        "    getsizeof() -- return the size of an object in bytes\n",
        "    gettrace() -- get the global debug tracing function\n",
        "    setcheckinterval() -- control how often the interpreter checks for events\n",
        "    setdlopenflags() -- set the flags to be used for dlopen() calls\n",
        "    setprofile() -- set the global profiling function\n",
        "    setrecursionlimit() -- set the max recursion depth for the interpreter\n",
        "    settrace() -- set the global debug tracing function\n",
        "\n",
        "FUNCTIONS\n",
        "    __displayhook__ = displayhook(...)\n",
        "        displayhook(object) -> None\n",
        "        \n",
        "        Print an object to sys.stdout and also save it in builtins._\n",
        "    \n",
        "    __excepthook__ = excepthook(...)\n",
        "        excepthook(exctype, value, traceback) -> None\n",
        "        \n",
        "        Handle an exception by displaying it with a traceback on sys.stderr.\n",
        "    \n",
        "    call_tracing(...)\n",
        "        call_tracing(func, args) -> object\n",
        "        \n",
        "        Call func(*args), while tracing is enabled.  The tracing state is\n",
        "        saved, and restored afterwards.  This is intended to be called from\n",
        "        a debugger from a checkpoint, to recursively debug some other code.\n",
        "    \n",
        "    callstats(...)\n",
        "        callstats() -> tuple of integers\n",
        "        \n",
        "        Return a tuple of function call statistics, if CALL_PROFILE was defined\n",
        "        when Python was built.  Otherwise, return None.\n",
        "        \n",
        "        When enabled, this function returns detailed, implementation-specific\n",
        "        details about the number of function calls executed. The return value is\n",
        "        a 11-tuple where the entries in the tuple are counts of:\n",
        "        0. all function calls\n",
        "        1. calls to PyFunction_Type objects\n",
        "        2. PyFunction calls that do not create an argument tuple\n",
        "        3. PyFunction calls that do not create an argument tuple\n",
        "           and bypass PyEval_EvalCodeEx()\n",
        "        4. PyMethod calls\n",
        "        5. PyMethod calls on bound methods\n",
        "        6. PyType calls\n",
        "        7. PyCFunction calls\n",
        "        8. generator calls\n",
        "        9. All other calls\n",
        "        10. Number of stack pops performed by call_function()\n",
        "    \n",
        "    exc_info(...)\n",
        "        exc_info() -> (type, value, traceback)\n",
        "        \n",
        "        Return information about the most recent exception caught by an except\n",
        "        clause in the current stack frame or in an older stack frame.\n",
        "    \n",
        "    exit(...)\n",
        "        exit([status])\n",
        "        \n",
        "        Exit the interpreter by raising SystemExit(status).\n",
        "        If the status is omitted or None, it defaults to zero (i.e., success).\n",
        "        If the status is an integer, it will be used as the system exit status.\n",
        "        If it is another kind of object, it will be printed and the system\n",
        "        exit status will be one (i.e., failure).\n",
        "    \n",
        "    getallocatedblocks(...)\n",
        "        getallocatedblocks() -> integer\n",
        "        \n",
        "        Return the number of memory blocks currently allocated, regardless of their\n",
        "        size.\n",
        "    \n",
        "    getcheckinterval(...)\n",
        "        getcheckinterval() -> current check interval; see setcheckinterval().\n",
        "    \n",
        "    getdefaultencoding(...)\n",
        "        getdefaultencoding() -> string\n",
        "        \n",
        "        Return the current default string encoding used by the Unicode \n",
        "        implementation.\n",
        "    \n",
        "    getdlopenflags(...)\n",
        "        getdlopenflags() -> int\n",
        "        \n",
        "        Return the current value of the flags that are used for dlopen calls.\n",
        "        The flag constants are defined in the os module.\n",
        "    \n",
        "    getfilesystemencoding(...)\n",
        "        getfilesystemencoding() -> string\n",
        "        \n",
        "        Return the encoding used to convert Unicode filenames in\n",
        "        operating system filenames.\n",
        "    \n",
        "    getprofile(...)\n",
        "        getprofile()\n",
        "        \n",
        "        Return the profiling function set with sys.setprofile.\n",
        "        See the profiler chapter in the library manual.\n",
        "    \n",
        "    getrecursionlimit(...)\n",
        "        getrecursionlimit()\n",
        "        \n",
        "        Return the current value of the recursion limit, the maximum depth\n",
        "        of the Python interpreter stack.  This limit prevents infinite\n",
        "        recursion from causing an overflow of the C stack and crashing Python.\n",
        "    \n",
        "    getrefcount(...)\n",
        "        getrefcount(object) -> integer\n",
        "        \n",
        "        Return the reference count of object.  The count returned is generally\n",
        "        one higher than you might expect, because it includes the (temporary)\n",
        "        reference as an argument to getrefcount().\n",
        "    \n",
        "    getsizeof(...)\n",
        "        getsizeof(object, default) -> int\n",
        "        \n",
        "        Return the size of object in bytes.\n",
        "    \n",
        "    getswitchinterval(...)\n",
        "        getswitchinterval() -> current thread switch interval; see setswitchinterval().\n",
        "    \n",
        "    gettrace(...)\n",
        "        gettrace()\n",
        "        \n",
        "        Return the global debug tracing function set with sys.settrace.\n",
        "        See the debugger chapter in the library manual.\n",
        "    \n",
        "    intern(...)\n",
        "        intern(string) -> string\n",
        "        \n",
        "        ``Intern'' the given string.  This enters the string in the (global)\n",
        "        table of interned strings whose purpose is to speed up dictionary lookups.\n",
        "        Return the string itself or the previously interned string object with the\n",
        "        same value.\n",
        "    \n",
        "    setcheckinterval(...)\n",
        "        setcheckinterval(n)\n",
        "        \n",
        "        Tell the Python interpreter to check for asynchronous events every\n",
        "        n instructions.  This also affects how often thread switches occur.\n",
        "    \n",
        "    setdlopenflags(...)\n",
        "        setdlopenflags(n) -> None\n",
        "        \n",
        "        Set the flags used by the interpreter for dlopen calls, such as when the\n",
        "        interpreter loads extension modules.  Among other things, this will enable\n",
        "        a lazy resolving of symbols when importing a module, if called as\n",
        "        sys.setdlopenflags(0).  To share symbols across extension modules, call as\n",
        "        sys.setdlopenflags(os.RTLD_GLOBAL).  Symbolic names for the flag modules\n",
        "        can be found in the os module (RTLD_xxx constants, e.g. os.RTLD_LAZY).\n",
        "    \n",
        "    setprofile(...)\n",
        "        setprofile(function)\n",
        "        \n",
        "        Set the profiling function.  It will be called on each function call\n",
        "        and return.  See the profiler chapter in the library manual.\n",
        "    \n",
        "    setrecursionlimit(...)\n",
        "        setrecursionlimit(n)\n",
        "        \n",
        "        Set the maximum depth of the Python interpreter stack to n.  This\n",
        "        limit prevents infinite recursion from causing an overflow of the C\n",
        "        stack and crashing Python.  The highest possible limit is platform-\n",
        "        dependent.\n",
        "    \n",
        "    setswitchinterval(...)\n",
        "        setswitchinterval(n)\n",
        "        \n",
        "        Set the ideal thread switching delay inside the Python interpreter\n",
        "        The actual frequency of switching threads can be lower if the\n",
        "        interpreter executes long sequences of uninterruptible code\n",
        "        (this is implementation-specific and workload-dependent).\n",
        "        \n",
        "        The parameter must represent the desired switching delay in seconds\n",
        "        A typical value is 0.005 (5 milliseconds).\n",
        "    \n",
        "    settrace(...)\n",
        "        settrace(function)\n",
        "        \n",
        "        Set the global debug tracing function.  It will be called on each\n",
        "        function call.  See the debugger chapter in the library manual.\n",
        "\n",
        "DATA\n",
        "    __stderr__ = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF...\n",
        "    __stdin__ = <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8...\n",
        "    __stdout__ = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF...\n",
        "    abiflags = 'm'\n",
        "    api_version = 1013\n",
        "    argv = ['-c', '-f', '/home/woodring/.ipython/profile_default/security/...\n",
        "    base_exec_prefix = '/usr'\n",
        "    base_prefix = '/usr'\n",
        "    builtin_module_names = ('_ast', '_codecs', '_collections', '_functools...\n",
        "    byteorder = 'little'\n",
        "    copyright = 'Copyright (c) 2001-2014 Python Software Foundati...ematis...\n",
        "    displayhook = <IPython.kernel.zmq.displayhook.ZMQShellDisplayHook obje...\n",
        "    dont_write_bytecode = False\n",
        "    exec_prefix = '/usr'\n",
        "    executable = '/usr/bin/python3'\n",
        "    flags = sys.flags(debug=0, inspect=0, interactive=0, opt...ing=0, quie...\n",
        "    float_info = sys.float_info(max=1.7976931348623157e+308, max_...epsilo...\n",
        "    float_repr_style = 'short'\n",
        "    hash_info = sys.hash_info(width=64, modulus=2305843009213693...iphash2...\n",
        "    hexversion = 50594544\n",
        "    implementation = namespace(cache_tag='cpython-34', hexversion=505...in...\n",
        "    int_info = sys.int_info(bits_per_digit=30, sizeof_digit=4)\n",
        "    last_value = UnboundLocalError(\"local variable 'foo' referenced before...\n",
        "    maxsize = 9223372036854775807\n",
        "    maxunicode = 1114111\n",
        "    meta_path = [<class '_frozen_importlib.BuiltinImporter'>, <class '_fro...\n",
        "    modules = {'IPython': <module 'IPython' from '/usr/lib/python3.4/site-...\n",
        "    path = ['', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/p...\n",
        "    path_hooks = [<class 'zipimport.zipimporter'>, <function FileFinder.pa...\n",
        "    path_importer_cache = {'/home/woodring/.ipython/extensions': FileFinde...\n",
        "    platform = 'linux'\n",
        "    prefix = '/usr'\n",
        "    ps1 = 'In : '\n",
        "    ps2 = '...: '\n",
        "    ps3 = 'Out: '\n",
        "    stderr = <IPython.kernel.zmq.iostream.OutStream object>\n",
        "    stdin = <_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>\n",
        "    stdout = <IPython.kernel.zmq.iostream.OutStream object>\n",
        "    thread_info = sys.thread_info(name='pthread', lock='semaphore', versio...\n",
        "    version = '3.4.2 (default, Oct  8 2014, 13:44:52) \\n[GCC 4.9.1 2014090...\n",
        "    version_info = sys.version_info(major=3, minor=4, micro=2, releaseleve...\n",
        "    warnoptions = []\n",
        "\n",
        "FILE\n",
        "    (built-in)\n",
        "\n",
        "\n",
        "None\n",
        "Help on built-in function exit in module sys:\n",
        "\n",
        "exit(...)\n",
        "    exit([status])\n",
        "    \n",
        "    Exit the interpreter by raising SystemExit(status).\n",
        "    If the status is omitted or None, it defaults to zero (i.e., success).\n",
        "    If the status is an integer, it will be used as the system exit status.\n",
        "    If it is another kind of object, it will be printed and the system\n",
        "    exit status will be one (i.e., failure).\n",
        "\n",
        "None\n"
       ]
      }
     ],
     "prompt_number": 30
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# import syntax\n",
      "\n",
      "import sys # bring all of sys into global namespace as sys\n",
      "print(sys.path) # use something in sys\n",
      "\n",
      "import sys as foobar # rename the sys module\n",
      "print(foobar.path)\n",
      "\n",
      "from sys import * # import everything from sys, without having to do sys.something\n",
      "from sys import path # only import path from sys\n",
      "print(path)\n",
      "\n",
      "from sys import path as foobar # import argv and rename it\n",
      "print(foobar)\n",
      "\n",
      "print(sys.path is foobar and path is foobar)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "['', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-linux', '/usr/lib/python3.4/lib-dynload', '/home/woodring/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages/IPython/extensions']\n",
        "['', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-linux', '/usr/lib/python3.4/lib-dynload', '/home/woodring/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages/IPython/extensions']\n",
        "['', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-linux', '/usr/lib/python3.4/lib-dynload', '/home/woodring/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages/IPython/extensions']\n",
        "['', '/usr/lib/python34.zip', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-linux', '/usr/lib/python3.4/lib-dynload', '/home/woodring/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages/IPython/extensions']\n",
        "True\n"
       ]
      }
     ],
     "prompt_number": 31
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# some final things to cover \n",
      "# (though, this isn't exhaustive, but a few more useful features)\n",
      "\n",
      "s = set([1, 1, 2, 3, 4, 4]) # sets\n",
      "print(s)\n",
      "print(3 in s)\n",
      "\n",
      "def plus_n(n):\n",
      "    return lambda x: x + n # lambdas are \"anonymous functions\"\n",
      "                           # though, limited to one line expressions in Python\n",
      "\n",
      "plus_two = plus_n(2) # make a plus two function\n",
      "print(plus_two, plus_two(1))\n",
      "        \n",
      "l = [2 ** i for i in range(0, 9) if i > 4] # list expressions\n",
      "                                           # basically, map and filter\n",
      "                                           # reduce is found in functools module\n",
      "print(l)\n",
      "\n",
      "# also, you can create \"generator functions\" for lazy\n",
      "# evaluation\n",
      "def infinite_evens():\n",
      "    i = 0\n",
      "    while True:\n",
      "        i = i + 2\n",
      "        yield i\n",
      "evens = infinite_evens() # infinite list of even numbers\n",
      "for i, j in zip(range(0, 10), evens):\n",
      "    print(i, j)\n",
      "\n",
      "try: # exception handling\n",
      "    print(undefined)\n",
      "except: # you can catch different types of exceptions\n",
      "        # which I am not showing here\n",
      "    print('I caught an error!')\n",
      "finally:\n",
      "    print('and some cleanup')\n",
      "\n",
      "# classes\n",
      "class test:\n",
      "    def __init__(self, k):\n",
      "        self.j = k\n",
      "    \n",
      "    def __call__(self):\n",
      "        return self.j\n",
      "    \n",
      "    def i(self, x):\n",
      "        self.j = x\n",
      "        return x + 1\n",
      "    \n",
      "t = test(10)\n",
      "print(t)\n",
      "print(t())\n",
      "print(t.i(2))\n",
      "print(t())\n",
      "t.foo = print\n",
      "t.foo('bar')\n",
      "print(dir(t))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "{1, 2, 3, 4}\n",
        "True\n",
        "<function plus_n.<locals>.<lambda> at 0x7faa08116e18> 3\n",
        "[32, 64, 128, 256]\n",
        "0 2\n",
        "1 4\n",
        "2 6\n",
        "3 8\n",
        "4 10\n",
        "5 12\n",
        "6 14\n",
        "7 16\n",
        "8 18\n",
        "9 20\n",
        "I caught an error!\n",
        "and some cleanup\n",
        "<__main__.test object at 0x7faa08143be0>\n",
        "10\n",
        "3\n",
        "2\n",
        "bar\n",
        "['__call__', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo', 'i', 'j']\n"
       ]
      }
     ],
     "prompt_number": 38
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# OK Break Time #\n",
      "## We'll take a break here before we get into the really fun stuff ##\n",
      "### Ask Questions, Try things out, Go to the Restroom ###\n",
      "### We'll pick up again in a few minutes ###"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# Running Python from the command line #\n",
      "\n",
      "```bash\n",
      "$ python some_program.py\n",
      "```\n",
      "\n",
      "It's as easy as that. If you are on bash, you can put `#!/usr/bin/python` on the first line of the program, and then launch it directly if the .py is set as executable.\n",
      "\n",
      "A better version is `#!/usr/bin/env python`, that way if you have different versions of Python, you can change your path to call the correct one.\n",
      "\n",
      "# Installing packages that you don't have #\n",
      "\n",
      "- With Anaconda Python\n",
      "```bash\n",
      "$ conda install <some package>\n",
      "```\n",
      "\n",
      "- With pip installed\n",
      "```bash\n",
      "$ pip install --user <some package>\n",
      "```\n",
      "\n",
      "## [PyPI](https://pypi.python.org/pypi) is the standard repository for Python packages ##"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# How do you create modules? #\n",
      "\n",
      "Just create a file named *your_module.py* and you can `import your_module`.\n",
      "\n",
      "Doing nested submodules is a little more involved, but not that hard. Check the python documentation.\n",
      "\n",
      "# How about main function? #\n",
      "\n",
      "You don't really need one, because eveything in the .py will be executed.\n",
      "\n",
      "Though, if you want an explicit main, here's the code for that:\n",
      "\n",
      "```python\n",
      "if __name__ == '__main__':\n",
      "    your code goes here\n",
      "```\n",
      "\n",
      "This is useful for putting unit tests directly into \"library\" code.\n",
      "\n",
      "# How about command line arguments? #\n",
      "\n",
      "Those are found in the *sys* module.\n",
      "\n",
      "```python\n",
      "import sys\n",
      "\n",
      "sys.argv # a list of command arguments\n",
      "sys.argv[0] # the name of the program\n",
      "sys.argv[1:] # everything else\n",
      "len(sys.argv) # number of arguments\n",
      "```\n",
      "\n",
      "There are standard modules for parsing command line arguments, to add switches, etc."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# what's next? numpy\n",
      "\n",
      "import numpy # also, it is standard convention to do\n",
      "             # import numpy as np\n",
      "             # I prefer typing numpy, as it is more explicit\n",
      "\n",
      "A = numpy.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n",
      "print(A)\n",
      "\n",
      "# OK, so what's so special about that compared to the list?"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[ 1  2  3  4  5  6  7  8  9 10]\n"
       ]
      }
     ],
     "prompt_number": 39
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# numpy arrays are fast, almost C speed\n",
      "# as long as you do \"large amounts of work\"\n",
      "\n",
      "import time\n",
      "\n",
      "AL = range(0, 1000000)\n",
      "BL = range(0, 1000000)\n",
      "CL = [0] * len(AL)\n",
      "\n",
      "start = time.time()\n",
      "for i in range(0, len(AL)):\n",
      "    CL[i] = AL[i] + BL[i]\n",
      "print(time.time() - start)\n",
      "\n",
      "A = numpy.array(range(0, 1000000), numpy.int32)\n",
      "B = numpy.array(range(0, 1000000), numpy.int32)\n",
      "\n",
      "start = time.time()\n",
      "C = A + B\n",
      "print(time.time() - start)\n"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "0.8321845531463623\n",
        "0.001194000244140625"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 40
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# numpy allows you to use lists (or any sequence) in place of an\n",
      "# array and it will convert it for you\n",
      "\n",
      "A = numpy.array([1, 2, 3, 4]) # initialized with a list\n",
      "B = [1, 2, 3, 4]\n",
      "C = A + B\n",
      "print(C)\n",
      "\n",
      "# but, it's better to start with arrays as your data structures\n",
      "# if you are going to be using them a lot, rather than converting\n",
      "\n",
      "# creating arrays from scratch\n",
      "A = numpy.empty((5,)) # length of 4\n",
      "A = numpy.empty((5,2)) # 4x2 matrix\n",
      "A = numpy.zeros((5,2)) # 4x2 matrix of zeroes\n",
      "A = numpy.zeros((5,2), numpy.float64) # 4x2 matrix of zeroes, using doubles\n",
      "\n",
      "# things need to be the name size (or shape) -- or \"broadcastable\"\n",
      "C = A + B # going to fail because A and B aren't the same shape"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[2 4 6 8]\n"
       ]
      },
      {
       "ename": "ValueError",
       "evalue": "operands could not be broadcast together with shapes (5,2) (4,) ",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-41-86277d246645>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     18\u001b[0m \u001b[1;31m# things need to be the name size (or shape) -- or \"broadcastable\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 19\u001b[1;33m \u001b[0mC\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mA\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mB\u001b[0m \u001b[1;31m# going to fail because A and B aren't the same shape\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;31mValueError\u001b[0m: operands could not be broadcast together with shapes (5,2) (4,) "
       ]
      }
     ],
     "prompt_number": 41
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# also, numpy has the ability to get binary data to and from disk\n",
      "\n",
      "f = open('foo.bin', 'w')\n",
      "a = numpy.array([1, 2, 3, 4, 5], numpy.int32)\n",
      "\n",
      "a.tofile(f)\n",
      "f.close()\n",
      "\n",
      "f = open('foo.bin', 'r')\n",
      "b = numpy.fromfile(f, numpy.int32, 5) \n",
      "\n",
      "f.close()\n",
      "\n",
      "print(a == b)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[ True  True  True  True  True]\n"
       ]
      }
     ],
     "prompt_number": 42
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# numpy notation is similar to array slicing\n",
      "# and Matlab and Fortran matrix notation\n",
      "\n",
      "A = numpy.array(range(0, 10)) # numbers 0..9\n",
      "\n",
      "V = A[::2] # this is a view (shallow copy)\n",
      "V[0] = -10 # slices are views in numpy\n",
      "print(V, A) \n",
      "B = A.copy() # this is a deep copy of A\n",
      "B[0] = 0\n",
      "print(B, A)\n",
      "\n",
      "C = A[::2] + B[::2]\n",
      "print(C)\n",
      "\n",
      "C = A[1:9] * B[:8]\n",
      "print(C)\n",
      "\n",
      "C = A[1:-3] - B[2:-2]\n",
      "print(C)\n",
      "\n",
      "C = A / B[:5] # this is going to fail, because they aren't the same shape"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[-10   2   4   6   8] [-10   1   2   3   4   5   6   7   8   9]\n",
        "[0 1 2 3 4 5 6 7 8 9] [-10   1   2   3   4   5   6   7   8   9]\n",
        "[-10   4   8  12  16]\n",
        "[ 0  2  6 12 20 30 42 56]\n",
        "[-1 -1 -1 -1 -1 -1]\n"
       ]
      },
      {
       "ename": "ValueError",
       "evalue": "operands could not be broadcast together with shapes (10,) (5,) ",
       "output_type": "pyerr",
       "traceback": [
        "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mValueError\u001b[0m                                Traceback (most recent call last)",
        "\u001b[1;32m<ipython-input-43-043c324e4d76>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m     20\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mC\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     21\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 22\u001b[1;33m \u001b[0mC\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mA\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mB\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;31m# this is going to fail, because they aren't the same shape\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
        "\u001b[1;31mValueError\u001b[0m: operands could not be broadcast together with shapes (10,) (5,) "
       ]
      }
     ],
     "prompt_number": 43
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# numpy also supports multi-dimensional arrays\n",
      "# default memory layout is:\n",
      "# C, row-major, right-most index varies fastest\n",
      "\n",
      "A = numpy.array(range(0, 8))\n",
      "A = numpy.reshape(A, (2, 2, 2)) # change the shape of an array\n",
      "                                # the total size (elements) must be the same\n",
      "print(A)\n",
      "\n",
      "print(A[0,0,0]) # this is different from nested lists\n",
      "print(A[1,1,1])\n",
      "\n",
      "A = numpy.transpose(A, axes=[0,2,1]) # swap around axes\n",
      "print(A)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[[[0 1]\n",
        "  [2 3]]\n",
        "\n",
        " [[4 5]\n",
        "  [6 7]]]\n",
        "0\n",
        "7\n",
        "[[[0 2]\n",
        "  [1 3]]\n",
        "\n",
        " [[4 6]\n",
        "  [5 7]]]\n"
       ]
      }
     ],
     "prompt_number": 44
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# numpy also supports \"broadcasting\"\n",
      "\n",
      "A = numpy.array(range(0, 4))\n",
      "A = numpy.reshape(A, (2, 2))\n",
      "\n",
      "print(A) # a 2x2 matrix\n",
      "\n",
      "A = A + 1 # 1 is added to all elements\n",
      "print(A)\n",
      "\n",
      "v = numpy.array([-1, 1]) # let's make a vector\n",
      "v = numpy.reshape(v, (2, 1)) # a column vector\n",
      "print(v)\n",
      "\n",
      "A = A * v # v gets broadcast over the columns\n",
      "print(A)\n",
      "\n",
      "v = numpy.reshape(v, (1, 2)) # now it's a row vector\n",
      "print(v)\n",
      "\n",
      "A = A - v # v gets broadcast over the rows\n",
      "print(A)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[[0 1]\n",
        " [2 3]]\n",
        "[[1 2]\n",
        " [3 4]]\n",
        "[[-1]\n",
        " [ 1]]\n",
        "[[-1 -2]\n",
        " [ 3  4]]\n",
        "[[-1  1]]\n",
        "[[ 0 -3]\n",
        " [ 4  3]]\n"
       ]
      }
     ],
     "prompt_number": 45
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# you can broadcast all sorts of ways\n",
      "\n",
      "A = numpy.array(range(0, 3*3))\n",
      "A = numpy.reshape(A, (3, 3))\n",
      "\n",
      "B = numpy.array(range(0, 3*1))\n",
      "B = numpy.reshape(B, (3, 1))\n",
      "\n",
      "C = A + B\n",
      "print(C)\n",
      "\n",
      "B = numpy.array(range(0, 3*1))\n",
      "B = numpy.reshape(B, (1, 3))\n",
      "\n",
      "C = A + B\n",
      "print(C)\n",
      "\n",
      "A = numpy.array(range(0, 2*2*2))\n",
      "A = numpy.reshape(A, (2, 2, 2))\n",
      "\n",
      "B = numpy.array(range(0, 2*1))\n",
      "B = numpy.reshape(B, (1, 1, 2))\n",
      "\n",
      "C = A + B\n",
      "print(C)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[[ 0  1  2]\n",
        " [ 4  5  6]\n",
        " [ 8  9 10]]\n",
        "[[ 0  2  4]\n",
        " [ 3  5  7]\n",
        " [ 6  8 10]]\n",
        "[[[0 2]\n",
        "  [2 4]]\n",
        "\n",
        " [[4 6]\n",
        "  [6 8]]]\n"
       ]
      }
     ],
     "prompt_number": 46
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# you can use 1D arrays to index into arrays\n",
      "\n",
      "A = numpy.array(range(0, 4))\n",
      "A = numpy.reshape(A, (2, 2))\n",
      "\n",
      "I = numpy.array([[0], [1], [1], [0]]) # the shape of the output\n",
      "J = numpy.array([[0], [0], [1], [1]]) # is the same shape as the indices shape\n",
      "print(A[I,J]) # (4, 1)\n",
      "print((A[I,J])[3,0])\n",
      "\n",
      "I = numpy.array([0, 1, 1, 0]) # the shape of the output\n",
      "J = numpy.array([0, 0, 1, 1]) # is the same shape as the indices\n",
      "print(A[I,J]) # (4,)\n",
      "print((A[I,J])[3])\n",
      "B = A[I,J]\n",
      "\n",
      "B[0] = 1000 # indexing creates a copy\n",
      "print(A, B)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[[0]\n",
        " [2]\n",
        " [3]\n",
        " [1]]\n",
        "1\n",
        "[0 2 3 1]\n",
        "1\n",
        "[[0 1]\n",
        " [2 3]] [1000    2    3    1]\n"
       ]
      }
     ],
     "prompt_number": 47
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# you can use boolean arrays to filter out elements\n",
      "A = numpy.array(range(1, 11))\n",
      "b = numpy.array([i % 2 == 0 for i in range(1, 11)]) # all the even elements\n",
      "\n",
      "print(A[b]) # b is the same shape as A\n",
      "            # this is stream compaction\n",
      "            # the output size is equal to the number of Trues\n",
      "\n",
      "print(numpy.where(b, A, 0)) # where generates the same shape as A\n",
      "                            # but replaces A with 0 where b is False\n",
      "\n",
      "print(A == 4) # this works\n",
      "print(A[b==False]) # and this too\n",
      "print(A[A > 5]) # and this\n",
      "\n",
      "print(numpy.argwhere(A > 5)) # get the indices where A > 5\n",
      "\n",
      "# there are other options as well, with any, all, logical_*\n",
      "# for doing all sorts of indexing"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[ 2  4  6  8 10]\n",
        "[ 0  2  0  4  0  6  0  8  0 10]\n",
        "[False False False  True False False False False False False]\n",
        "[1 3 5 7 9]\n",
        "[ 6  7  8  9 10]\n",
        "[[5]\n",
        " [6]\n",
        " [7]\n",
        " [8]\n",
        " [9]]\n"
       ]
      }
     ],
     "prompt_number": 48
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# numpy has a lot of functionality\n",
      "# beyond +, *, - and /\n",
      "# http://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs\n",
      "\n",
      "A = numpy.array(range(0, 4))\n",
      "\n",
      "print(numpy.max(A))\n",
      "print(numpy.min(A))\n",
      "print(numpy.sign(A))\n",
      "print(numpy.cos(A))\n",
      "print(A > A)\n",
      "print(A == A)\n",
      "print(-A)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "3\n",
        "0\n",
        "[0 1 1 1]\n",
        "[ 1.          0.54030231 -0.41614684 -0.9899925 ]\n",
        "[False False False False]\n",
        "[ True  True  True  True]\n",
        "[ 0 -1 -2 -3]\n"
       ]
      }
     ],
     "prompt_number": 49
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# and a lot of what you want is probably\n",
      "# in the linear algebra\n",
      "# http://docs.scipy.org/doc/numpy/reference/routines.linalg.html\n",
      "    \n",
      "from numpy.linalg import linalg # a submodule of a module\n",
      "# numpy.linalg.linalg \n",
      "\n",
      "A = numpy.array([[0, 1], [2, 3]])\n",
      "B = numpy.array([[0, -1], [1, 0]])\n",
      "\n",
      "print(linalg.dot(A, B)) # matrix multiply\n",
      "print(numpy.outer(A, B)) # outer product\n",
      "print(linalg.qr(A)) # qr factorization\n",
      "print(linalg.svd(A)) # SVD\n",
      "print(linalg.eig(A)) # eigenvectors and values\n",
      "print(linalg.inv(A)) # inverse of A\n",
      "# etc. "
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[[ 1  0]\n",
        " [ 3 -2]]\n",
        "[[ 0  0  0  0]\n",
        " [ 0 -1  1  0]\n",
        " [ 0 -2  2  0]\n",
        " [ 0 -3  3  0]]\n",
        "(array([[ 0., -1.],\n",
        "       [-1.,  0.]]), array([[-2., -3.],\n",
        "       [ 0., -1.]]))\n",
        "(array([[-0.22975292, -0.97324899],\n",
        "       [-0.97324899,  0.22975292]]), array([ 3.70245917,  0.54018151]), array([[-0.52573111, -0.85065081],\n",
        "       [ 0.85065081, -0.52573111]]))\n",
        "(array([-0.56155281,  3.56155281]), array([[-0.87192821, -0.27032301],\n",
        "       [ 0.48963374, -0.96276969]]))"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n",
        "[[-1.5  0.5]\n",
        " [ 1.   0. ]]\n"
       ]
      }
     ],
     "prompt_number": 50
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# next is scipy\n",
      "#\n",
      "# it has lots of specialized functionality\n",
      "# for scientific computing:\n",
      "# FFTs, signal processing, integration, statistics,\n",
      "# interpolation, optimization, graphs, etc.\n",
      "#\n",
      "# http://docs.scipy.org/doc/scipy/reference/\n",
      "\n",
      "from scipy import fftpack\n",
      "\n",
      "A = numpy.array([0, 1, 2, 3, 4, 3, 2, 1])\n",
      "\n",
      "print(fftpack.fft(A)) # fft\n",
      "print(fftpack.ifft(fftpack.fft(A))) # ifft and fft\n",
      "\n",
      "from scipy import optimize\n",
      "\n",
      "B = numpy.array([0, 1, 2, 3, 4, 5, 6, 7])\n",
      "\n",
      "def poly(x, a, b, c): # the model to fit to\n",
      "    return a + b*x + c*x*x\n",
      "\n",
      "print(optimize.curve_fit(poly, B, A)) # outputs a, b, c and covariance matrix"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "[ 16.00000000 +0.00000000e+00j  -6.82842712 -2.22044605e-16j\n",
        "   0.00000000 -0.00000000e+00j  -1.17157288 -2.22044605e-16j\n",
        "   0.00000000 +0.00000000e+00j  -1.17157288 +2.22044605e-16j\n",
        "   0.00000000 +0.00000000e+00j  -6.82842712 +2.22044605e-16j]\n",
        "[ 0. +0.00000000e+00j  1. +5.55111512e-17j  2. +0.00000000e+00j\n",
        "  3. -1.11022302e-16j  4. +0.00000000e+00j  3. -5.55111512e-17j\n",
        "  2. +0.00000000e+00j  1. +1.11022302e-16j]\n",
        "(array([-0.33333333,  1.85714286, -0.23809524]), array([[ 0.13492064, -0.07142857,  0.00793651],\n",
        "       [-0.07142857,  0.0600907 , -0.00793651],\n",
        "       [ 0.00793651, -0.00793651,  0.00113379]]))"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "\n"
       ]
      }
     ],
     "prompt_number": 51
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# the fun part, plotting the data\n",
      "\n",
      "%matplotlib inline \n",
      "# this \"magic\" is necessary for ipython notebook\n",
      "# it's not necessary (and will be an error)\n",
      "# in normal python\n",
      "\n",
      "# there are other \"magic\" ipython commands, check the documentation\n",
      "\n",
      "import matplotlib.pyplot as plt # this is all you need in python\n",
      "                                # pyplot is the Matlab like plotting interface\n",
      "                                # plt is the standard rename for pyplot\n",
      "    \n",
      "# examples of plots can be found at http://matplotlib.org/gallery.html"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 52
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import functools\n",
      "\n",
      "A = numpy.array([0, 1, 2, 3, 4, 3, 2, 1])\n",
      "B = numpy.array([0, 1, 2, 3, 4, 5, 6, 7])\n",
      "\n",
      "# our model curve\n",
      "def poly(x, a, b, c):\n",
      "    return a + b*x + c*x*x\n",
      "\n",
      "abc, cov = optimize.curve_fit(poly, B, A) # going to do the least squares fit like before\n",
      "\n",
      "fixed = functools.partial(poly, a=abc[0], b=abc[1], c=abc[2]) # freeze the polynomial\n",
      "fixed = numpy.vectorize(fixed) # create a vectorized version of the function\n",
      "\n",
      "# the start of a plot\n",
      "# pyplot is Matlab like, it is a state machine\n",
      "plt.figure() # start a new plot\n",
      "plt.xlabel('x') # labels\n",
      "plt.ylabel('y')\n",
      "plt.plot(B, fixed(B)) # the x and y values of the model\n",
      "plt.legend('model')\n",
      "plt.plot(B, A, 'o') # 'o' means plot it with circles\n",
      "plt.legend('original')\n",
      "plt.title('least squares fit to quadratic model') # a title\n",
      "plt.show() # show it\n",
      "\n",
      "# plt.savefig('foo.png') # write it to an image instead"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\n",
       "text": [
        "<matplotlib.figure.Figure at 0x7fa9e855cc18>"
       ]
      }
     ],
     "prompt_number": 53
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from scipy import fftpack\n",
      "from scipy import fft\n",
      "\n",
      "A = numpy.array([0, 1, 0, -1, 0, 1, 0, -1])\n",
      "\n",
      "f = numpy.abs(fftpack.fft(A)) ** 2 # power spectrum\n",
      "q = fftpack.fftfreq(A.size, 1.0) # get the frequencies\n",
      "i = numpy.argsort(q) # get the indices that would sort the frequencies\n",
      "\n",
      "plt.figure() # plot it\n",
      "plt.title('power spectrum')\n",
      "plt.xlabel('frequencies')\n",
      "plt.ylabel('power')\n",
      "plt.plot(q[i], f[i]) \n",
      "plt.show()"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\nQmCC\n",
       "text": [
        "<matplotlib.figure.Figure at 0x7faa081347f0>"
       ]
      }
     ],
     "prompt_number": 54
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "# sqlite is awesome to store your data in\n",
      "# stop using custom text files, and use sqlite\n",
      "\n",
      "import sqlite3\n",
      "conn = sqlite3.connect('northwind.db') # connect to the database\n",
      "cursor = conn.cursor()\n",
      "\n",
      "cursor.execute('select CustomerID from customers')\n",
      "# this is a pretty simple query, but you can do all sorts\n",
      "# of complex SQL queries, using SQLite\n",
      "\n",
      "# convert the first letter of the customer id to a number\n",
      "data = cursor.fetchall()\n",
      "customers = [ord(i[0][0]) - ord('A') + 1 for i in data]\n",
      "bins = numpy.max(customers) - numpy.min(customers)\n",
      "\n",
      "# let's plot the distribution\n",
      "plt.figure()\n",
      "plt.title('distribution of customer ids')\n",
      "plt.xlabel('first letter')\n",
      "plt.ylabel('count')\n",
      "plt.hist(customers, bins)\n",
      "plt.show()\n",
      "\n",
      "# what's the max letter?\n",
      "counts = numpy.histogram(customers, bins)[0]\n",
      "print(chr(numpy.argmax(counts) + numpy.min(customers) + ord('A')))"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\nJQ82pQAAAABJRU5ErkJggg==\n",
       "text": [
        "<matplotlib.figure.Figure at 0x7fa9e8194d68>"
       ]
      },
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "W\n"
       ]
      }
     ],
     "prompt_number": 55
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# Where to go from here? #\n",
      "\n",
      "- Lots of features I didn't cover in Matplotlib: [Matplotlib Gallery](http://matplotlib.org/gallery.html)\n",
      "- Matplotlib can do 3D visualization\n",
      "- More powerful 3D visualization is available through [VTK](http://vtk.org) and [ParaView](http://paraview.org) bindings\n",
      "- Example of a really cool and sophisticated visualization and analysis toolchain, checkout [yt](http://yt-project.org/) for Cosmological and Astrophyics analysis\n",
      "- To do web style graphics, try [Bokeh](http://bokeh.pydata.org/)\n",
      "- You can even script [Blender](http://www.blender.org/documentation/blender_python_api_2_72_release/#blender-python-documentation) for modeling and rendering\n",
      "- If you'd rather do it from scratch, there's [PyOpenGL](http://pyopengl.sourceforge.net/)\n",
      "- Also, if you're interested, theres [PyGame](http://www.pygame.org/news.html) bindings to the SDL library\n",
      "- For data sources, there's tons of bindings to SQL style databases, HDF5, NetCDF, etc. First, try using SQLite3. While it won't scale, it will certainly make smaller data sets managable\n",
      "- For big data, cloud databases, etc. try [Blaze](http://blaze.pydata.org/docs/latest/index.html)\n",
      "- For GUIs, try [PyQt](https://wiki.python.org/moin/PyQt) (there are other options as well)\n",
      "\n",
      "## And the list goes on, and on, and on... ##\n"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# Now go out and write some Python #\n",
      "\n",
      "- From my experience at the lab, there are so many problems that can be solved just with a \"scripting\" language\n",
      "- Though, it's unfair to call Python scripting, as many applications are written in Python as the main language\n",
      "\n",
      "## Too many problems are prematurely optimized ##\n",
      "\n",
      "- For example, in visualization and analysis, a lot the bottleneck is in the I/O\n",
      "- Then, Python will typically go almost as fast as C \n",
      "- Faster turn around time in your research if you rapid prototype, and then find the bottlenecks\n",
      "- But, Python won't solve all your problems, especially if you are CPU bound or memory-bandwidth bound"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "# Thanks for your time #\n",
      "## Questions? ##"
     ]
    }
   ],
   "metadata": {}
  }
 ]
}