{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [ "%autosave 10" ], "language": "python", "metadata": {}, "outputs": [ { "javascript": [ "IPython.notebook.set_autosave_interval(10000)" ], "metadata": {}, "output_type": "display_data" }, { "output_type": "stream", "stream": "stdout", "text": [ "Autosaving every 10 seconds\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "(wait for IPython Notebook to get posted) \n", "- !!AI look in 2013-talks, found a copy of the talk. go through it make notes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##\u00a0Background" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def f(x):\n", " return x+1, x+2\n", "f(10) == (11, 12)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 2, "text": [ "True" ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "def f(x):\n", " yield x+1\n", " yield x+2\n", "list(f(10)) == [11, 12]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "True" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Generators require iteration over results." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Callable" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Callable(object):\n", " def __call__(self, x):\n", " return x+1, x+2\n", "Callable()(10) == (11, 12)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "True" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Iterable\n", "\n", "- `__iter__`, `__next__`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Generators\n", "\n", "At the C-level, generators are functions that leave state behind when yielding. It just jumps over the cleanup." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Coroutines\n", "\n", "- Functions have one entry, one exit, and eagerly return results.\n", "- Coroutines have multiple entries, multiple exits, and lazily return results.\n", "- `throw`, `send`, `close`.\n", " - `throw`: throw exception during iteration.\n", " - `close`: halt a generator, clean up state.\n", " - `send`: send value back into a generator." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " y = None\n", " y = yield x+1, y\n", " y = yield x+1, y\n", "\n", "g = generator(10)\n", "print g.next()\n", "print g.send(\"abc\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(11, None)\n", "(11, 'abc')\n" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pumping and priming\n", "\n", "- One annoyance.\n", "- Can't inject value before first yield into a generator/coroutine.\n", "- \"Can't send non-None to a just-started generator\"\n", "- You'll see \"pump\" or \"prime\" decorator in large projects.\n", "\n", "## Itertools\n", "\n", "- 2nd out of 23 favourite Python modules.\n", "- Generators is one of the core features of Python.\n", "- `izip`, `islice` help you manipulate iterables without caring about their contents.\n", " - e.g. can't concatenate a list and a tuple natively.\n", " - but `chain` just connects iterables, doesn't care.\n", "- Want to dscompose problem into composition of streams, and don't need to bring everything into memory." ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }