{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "I. Introductions" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "II. Functions vs Generators (vs Generator Expressions vs Iterables)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Functions" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "A typical function definition looks like the below. In this case, we return two values as a tuple. We use this function by calling it with ().\n", "\n", "In Python, functions are generalised as \"callables\" and support the __call__ protocol. Many different things are callables (classes, C-functions, generators, &c.)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def function(x):\n", " return x+1, x+2\n", "\n", "assert function(10) == (11,12)\n", "\n", "# example usage\n", "answer = function(10)\n", "print 'function(100) -> {}'.format(answer)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "function(100) -> (11, 12)\n" ] } ], "prompt_number": 7 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Generators" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "A typical generator definition looks like the below. We swap out the `return` statement with a `yield statement` and provide two values. We use this generator by instantiating it with () then iterating over it.\n", "\n", "In Python, generators are generalised as \"iterables\" and support the __iter__/__next__ protocols. Many different things are iterable (lists, tuples, dictionaries, generators, &c.)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " yield x+1\n", " yield x+2\n", "\n", "assert list(generator(10)) == [11, 12]\n", "\n", "# example usage\n", "for x in generator(10):\n", " print 'generator(10) -> {}'.format(x)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "generator(10) -> 11\n", "generator(10) -> 12\n" ] } ], "prompt_number": 9 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Generator Expressions" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "We may note that a generator defined with `yield`-syntax appears to support both the __call__ and __iter__/__next__ protocols. In this case, we __call__ the generator to create an instance, then we iterate over the instance.\n", "\n", "A generator expression is one way we can construct a single instance inline." ] }, { "cell_type": "code", "collapsed": false, "input": [ "generator_expression = (x+1 for x in [1,2,4,8,16])\n", "\n", "assert list(generator_expression) == [2,3,5,9,17]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "generator_expression = (x+1 for x in [1,2,4,8,16])\n", "\n", "# example usage\n", "for x in generator_expression:\n", " print 'generator_expression -> {}'.format(x)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "generator_expression -> 2\n", "generator_expression -> 3\n", "generator_expression -> 5\n", "generator_expression -> 9\n", "generator_expression -> 17\n" ] } ], "prompt_number": 11 }, { "cell_type": "raw", "metadata": {}, "source": [ "A generator defined with `yield`-syntax is not strictly the same as, but can be considered equivalent with a generator expression that is constructed dynamically behind a lambda." ] }, { "cell_type": "code", "collapsed": false, "input": [ "generator_expression = lambda: (x+1 for x in [1,2,4,8,16])\n", "\n", "assert list(generator_expression()) == [2,3,5,9,17]\n", "\n", "# example usage\n", "for x in generator_expression():\n", " print 'generator_expression() -> {}'.format(x)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "generator_expression() -> 2\n", "generator_expression() -> 3\n", "generator_expression() -> 5\n", "generator_expression() -> 9\n", "generator_expression() -> 17\n" ] } ], "prompt_number": 13 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Iterables" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Callables are the Python generalisation of functions. \n", "\n", "In Python a callable is just some object that supports the __call__ protocol. __call__ corresponds to () or apply()" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Callable(object):\n", " def __call__(self, x):\n", " return x + 1, x + 2\n", "\n", "assert Callable()(10) == (11, 12)\n", "\n", "# exampe usage\n", "answer = Callable()(10)\n", "print 'Callable(10) -> {}'.format(answer)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Callable(10) -> (11, 12)\n" ] } ], "prompt_number": 17 }, { "cell_type": "raw", "metadata": {}, "source": [ "What if __call__ is a staticmethod?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class Callable(object):\n", " @staticmethod\n", " def __call__(x):\n", " return x + 1, x + 2\n", "\n", "assert Callable()(10) == (11, 12)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "from collections import Callable\n", "\n", "def function():\n", " pass\n", "\n", "assert callable(function) # deprecated in Python 3\n", "assert isinstance(function, Callable)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 22 }, { "cell_type": "raw", "metadata": {}, "source": [ "Iterables are the Python generalisation of lists, tuples, &c.\n", "\n", "In Python an iterable is just some object that supports the __iter__ protocol and returns an object which supports the __next__ protocol. __iter__ corresponds to iter() and __next__ corresponds to next()\n", "\n", "Note that in Python 2, the __next__ protocol is provided by next. This was fixed in Python 3 (which we should all be using.)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "some_list = [1, 1, 2, 3, 5]\n", "\n", "for x in some_list:\n", " print 'some_list -> {}'.format(x)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "some_list -> 1\n", "some_list -> 1\n", "some_list -> 2\n", "some_list -> 3\n", "some_list -> 5\n" ] } ], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "class Iterable(object):\n", " def __init__(self, x):\n", " self.x = x\n", " self.state = 0\n", " def __iter__(self):\n", " return self # this object is both an iterator and an iterable\n", " def __next__(self):\n", " if self.state == 2:\n", " raise StopIteration\n", " rv = self.x + self.state\n", " self.state += 1\n", " return rv\n", " next = __next__ # Python 3 calls it `__next__`; Python 2 calls it `next`\n", " \n", "assert list(Iterable(10)) == [10, 11]\n", "\n", "# example usage\n", "for x in Iterable(10):\n", " print 'Iterable(10) -> {}'.format(x)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Iterable(10) -> 10\n", "Iterable(10) -> 11\n" ] } ], "prompt_number": 29 }, { "cell_type": "raw", "metadata": {}, "source": [ "Note that, in the above, we have an instance member called `self.state` that tracks the state.\n", "\n", "An iterator is anything that can be iterated over.\n", "\n", "An iterable is merely some object that tracks the state of the iteration." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from collections import Iterator, Iterable\n", "\n", "some_list = [1, 1, 2, 3, 5]\n", "assert isinstance(some_list, Iterable) and not isinstance(some_list, Iterator)\n", "\n", "some_iter = iter(some_list)\n", "assert isinstance(some_iter, Iterable) and isinstance(some_iter, Iterator)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 33 }, { "cell_type": "raw", "metadata": {}, "source": [ "A generator is merely a much lower-level expression of the above.\n", "\n", "Instead of explicitly tracking the state with some instance member, the state is tracked by a frame object which tracks the last line of code executed." ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "III. Coroutines" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "The generator below can `yield` values. This is in correspondence to how a function can `return` values." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " yield x+1\n", " yield x+2\n", "\n", "assert list(generator(10)) == [11, 12]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 34 }, { "cell_type": "raw", "metadata": {}, "source": [ "We can also send values into a generator at any point during the iteration. This is what makes a generator a coroutine.\n", "\n", "In fact, generators support a rich protocol including:\n", "\n", ".next: get the next value\n", ".throw: raise an exception\n", ".send: send a value in\n", ".close: terminate iteration" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "next & .next" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " yield x+1\n", " yield x+2\n", "\n", "assert list(generator(10)) == [11, 12]\n", " \n", "# support for next(), .next()\n", "g = generator(10)\n", "print 'next(g) -> {}'.format(next(g)) # these two lines are \n", "print 'next(g) -> {}'.format(g.next())\n", "\n", "# next too many times, and we get a StopIteration\n", "try:\n", " next(g)\n", "except StopIteration as e:\n", " print 'next(g) -> {!r}'.format(e)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "next(g) -> 11\n", "next(g) -> 12\n", "next(g) -> StopIteration()\n" ] } ], "prompt_number": 41 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ ".throw" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sys import exc_info\n", "from traceback import print_tb\n", "\n", "def generator(x):\n", " yield x+1\n", " yield x+2\n", "\n", "g = generator(10)\n", "print 'next(g) -> {}'.format(next(g))\n", "# print 'next(g) -> {}'.format(next(g))\n", "\n", "# support for .throw\n", "try:\n", " g.throw(ValueError('raised value error'))\n", "except ValueError as e:\n", " print 'g.throw(ValueError) -> {!r}'.format(e)\n", " _, _, traceback = exc_info()\n", " print_tb(traceback)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "next(g) -> 11\n", "g.throw(ValueError) -> ValueError('raised value error',)\n" ] }, { "output_type": "stream", "stream": "stderr", "text": [ " File \"\", line 14, in \n", " g.throw(ValueError('raised value error'))\n", " File \"\", line 5, in generator\n", " yield x+1\n" ] } ], "prompt_number": 53 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ ".close" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " yield x+1\n", " yield x+2\n", "\n", "g = generator(10)\n", "print 'next(g) -> {}'.format(next(g))\n", "\n", "g.close()\n", "\n", "try:\n", " next(g)\n", "except StopIteration as e:\n", " print 'g.close()'\n", " print 'next(g) -> {!r}'.format(e)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "next(g) -> 11\n", "g.close()\n", "next(g) -> StopIteration()\n" ] } ], "prompt_number": 57 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ ".send" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "next(g) is the same as g.next()\n", "\n", "These are the same as g.send(None) or g.send()\n", "\n", "g.send() sends a value back into the generator at the point of `yield`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " y = None\n", " y = yield x+1, y\n", " y = yield x+2, y\n", "\n", "g = generator(10)\n", "print 'next(g) -> {}'.format( g.next() )\n", "print 'g.send(\"abc\") -> {}'.format( g.send(\"abc\") )" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "next(g) -> (11, None)\n", "g.send(\"abc\") -> (12, 'abc')\n" ] } ], "prompt_number": 59 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "pumping & priming" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "One annoyance of generators is that we retrieve a value sent into the generator on the left hand side of a `yield`.\n", "\n", "This means that we must `yield` a value before we can accept a value back in.\n", "\n", "As a result, we have the following problem." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def generator(x):\n", " yield x + 1\n", " \n", "g = generator(10)\n", "g.send(10)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "can't send non-None value to a just-started generator", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mg\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgenerator\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: can't send non-None value to a just-started generator" ] } ], "prompt_number": 61 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "IV. Itertools" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Itertools is an extremely useful collection of utilities in the standard library.\n", "\n", "It contains very efficient generalisations, helpers, and algorithms that allow us to work very effectively with generators.\n", "\n", "The contents of itertools are themselves not generators; they are written in C and are mostly standard Python C-functions and C-objects." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "generalisation" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# an example of a generalisation: slicing\n", "from itertools import islice\n", "\n", "# standard lists can be sliced\n", "some_list = [1, 1, 2, 3, 5, 8]\n", "print some_list[1:5]\n", "\n", "# abstract iterables can be isliced\n", "def fibonacci(a=1, b=1):\n", " while True:\n", " yield a\n", " a, b = b, a+b\n", "\n", "print list(islice(fibonacci(),1,5))\n", "\n", "# other examples: izip, imap, ifilter (Python2)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 2, 3, 5]\n", "[1, 2, 3, 5]\n" ] } ], "prompt_number": 3 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "helper" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# an example of a helper: chain\n", "from itertools import chain, islice\n", "\n", "# standard lists can be appended\n", "some_list = [1, 1, 2, 3, 5, 8]\n", "some_list = [0] + some_list\n", "print some_list\n", "\n", "# abstract iterables can be chained\n", "def fibonacci(a=1, b=1):\n", " while True:\n", " yield a\n", " a, b = b, a+b\n", " \n", "f = fibonacci()\n", "f = chain([0], f)\n", "\n", "print list(islice(f,0,7))\n", "\n", "# other examples: tee, repeat, cycle" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[0, 1, 1, 2, 3, 5, 8]\n", "[0, 1, 1, 2, 3, 5, 8]\n" ] } ], "prompt_number": 4 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "algorithm" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# an example of an algorithm: takewhile\n", "from itertools import takewhile\n", "\n", "# take elements as long as some predicate is True\n", "def fibonacci(a=1, b=1):\n", " while True:\n", " yield a\n", " a, b = b, a+b\n", "\n", "print list(takewhile(lambda n: n < 50, fibonacci()))\n", "\n", "# other examples: dropwhile, product, combinations, permutations" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 1, 2, 3, 5, 8, 13, 21, 34]\n" ] } ], "prompt_number": 7 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "V. Efficiency" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "One reason to use generators is that they can efficiently represent certain constructs." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "memory efficiency" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "For algorithms that require the use of only a subset of the entire return value, generators can prove far more memory efficient than their functional equivalents." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def pairwise(xs):\n", " xs = iter(xs)\n", " pairings = []\n", " x = next(xs)\n", " for y in xs:\n", " pairings.append([x,y])\n", " x = y\n", " return pairings\n", "\n", "print pairwise(xrange(10))\n", "# print pairwise(xrange(1000000))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]\n" ] } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "def pairwise(xs):\n", " xs = iter(xs)\n", " x = next(xs)\n", " for y in xs:\n", " yield x, y\n", " x = y\n", "\n", "print list(pairwise(xrange(10)))\n", "print pairwise(xrange(1000000))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]\n", "\n" ] } ], "prompt_number": 1 }, { "cell_type": "raw", "metadata": {}, "source": [ "Note that this can be written very tersely and very generically by combining helpers from `itertools`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from itertools import tee, izip, islice\n", "nwise = lambda g,n=2: izip(*(islice(g,i,None) for i,g in enumerate(tee(g,n))))\n", "\n", "print list(nwise(xrange(10)))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)]\n" ] } ], "prompt_number": 20 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "time efficiency" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Generators tend to be fairly efficient in practice: vs " ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import ceil, sqrt\n", "isprime = lambda n: 1 < n < 4 or all(n % d for d in xrange(2,int(ceil(sqrt(n)))+1,2))\n", " \n", "%timeit -n100 isprime(11984395091324)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "100 loops, best of 3: 2.22 us per loop\n" ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "from math import ceil, sqrt\n", "def isprime(n):\n", " if 1 < n < 4:\n", " return True\n", " for d in xrange(2, int(ceil(sqrt(n)))+1, 2):\n", " if n % d == 0:\n", " return False\n", " return True\n", "\n", "%timeit -n100 isprime(11984395091324)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "100 loops, best of 3: 1.33 us per loop\n" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "from math import ceil, sqrt\n", "isprime = lambda n, ng: 1 < n < 4 or all(ng)\n", " \n", "n = 11984395091324\n", "ng = (n % d for d in xrange(2,int(ceil(sqrt(n)))+1,2))\n", "\n", "%timeit -n100 isprime(n, ng)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "100 loops, best of 3: 200 ns per loop\n" ] } ], "prompt_number": 4 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "structural considerations" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Generators are opaque building-blocks, so they can be swapped out very easily with more efficient representations: " ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "VI. Modelling" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Someone asked me about numpy arrays versus generators.\n", "\n", "Numpy arrays are both efficient in practice and also very convenient to use.\n", "\n", "While generators can be very efficient and convenient, their real draw is in the ability to better model problems." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "stream data processing & pipeline flow" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "Generators allow us to model programmes with a stream processing or pipeline conceptualisation." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "presumptions about return type" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def fibonacci(n, a=1, b=1):\n", " rv = [a, b]\n", " while rv[-1] + rv[-2] < n:\n", " rv.append(rv[-1] + rv[-2])\n", " return rv\n", "\n", "print fibonacci(20)\n", "print set(fibonacci(20))\n", "print tuple(fibonacci(20))\n", "\n", "% timeit fibonacci(20000)\n", "% timeit set(fibonacci(20000))\n", "% timeit tuple(fibonacci(20000))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 1, 2, 3, 5, 8, 13, 21]\n", "set([1, 2, 3, 5, 8, 13, 21])\n", "(1, 1, 2, 3, 5, 8, 13, 21)\n", "100000 loops, best of 3: 3.11 us per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "100000 loops, best of 3: 4.27 us per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "100000 loops, best of 3: 3.31 us per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 56 }, { "cell_type": "code", "collapsed": false, "input": [ "def fibonacci(n, a=1, b=1):\n", " while a < n:\n", " yield a\n", " a, b = b, a+b\n", "\n", "print list(fibonacci(20))\n", "print set(fibonacci(20))\n", "print tuple(fibonacci(20))\n", "\n", "%timeit set(fibonacci(20000))\n", "%timeit list(fibonacci(20000))\n", "%timeit tuple(fibonacci(20000))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 1, 2, 3, 5, 8, 13]\n", "set([1, 2, 3, 5, 8, 13])\n", "(1, 1, 2, 3, 5, 8, 13)\n", "100000 loops, best of 3: 2.79 us per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "100000 loops, best of 3: 2.8 us per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "100000 loops, best of 3: 2.53 us per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 58 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "presumptions about return values" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# fibonacci numbers up to but not exceeding n\n", "def fibonacci(n, a=1, b=1):\n", " rv = [a, b]\n", " while rv[-1] + rv[-2] < n:\n", " rv.append(rv[-1] + rv[-2])\n", " return rv\n", " \n", "print fibonacci(20)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 1, 2, 3, 5, 8, 13]\n" ] } ], "prompt_number": 62 }, { "cell_type": "code", "collapsed": false, "input": [ "# fibonacci numbers up to but not exceeding n\n", "def fibonacci(n, a=1, b=1):\n", " rv = [a, b]\n", " for _ in xrange(2,n):\n", " rv.append(rv[-1] + rv[-2])\n", " return rv\n", "\n", "print fibonacci(20)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]\n" ] } ], "prompt_number": 63 }, { "cell_type": "code", "collapsed": false, "input": [ "from itertools import takewhile, islice\n", "\n", "def fibonacci(a=1, b=1):\n", " while True:\n", " yield a\n", " a, b = b, a+b\n", "\n", "print list(islice(fibonacci(), 0, 20)) # first twenty values\n", "print list(takewhile(lambda n: n < 20, fibonacci())) # values up to but not exceeding 20" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765]\n", "[1, 1, 2, 3, 5, 8, 13]\n" ] } ], "prompt_number": 65 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "presumptions about use of values" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from time import sleep\n", "\n", "# fibonacci numbers up to but not exceeding n\n", "def fibonacci(n, a=1, b=1):\n", " rv = [a, b]\n", " for _ in xrange(2,n):\n", " rv.append(rv[-1] + rv[-2])\n", " sleep(.01)\n", " return rv\n", "\n", "print fibonacci(20)[0]\n", "% timeit fibonacci(20)[0]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1\n", "10 loops, best of 3: 182 ms per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 67 }, { "cell_type": "code", "collapsed": false, "input": [ "from time import sleep\n", "\n", "def fibonacci(a=1, b=1):\n", " while True:\n", " yield a\n", " a, b = b, a+b\n", " sleep(.01)\n", "\n", "print next(fibonacci())\n", "% timeit next(fibonacci())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1\n", "1000000 loops, best of 3: 390 ns per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 68 }, { "cell_type": "code", "collapsed": false, "input": [ "from datetime import date, timedelta\n", "from time import sleep\n", "\n", "holidays = { 'new years': date(2013, 1, 1),\n", " 'mlk day': date(2013, 1, 21),\n", " 'presidents day': date(2013, 2, 18),\n", " 'good friday': date(2013, 3, 29),\n", " 'memorial': date(2013, 5, 27),\n", " 'independence day': date(2013, 6, 4),\n", " 'labour day': date(2013, 9, 2),\n", " 'columbus day': date(2013, 10, 14),\n", " 'veterans day': date(2013, 11, 11),\n", " 'thanksgiving': date(2013, 11, 29),\n", " 'christmas': date(2013, 12, 24) }\n", "\n", "def next_business_day(refdate, n=1, holidays=set(holidays.values())):\n", " sleep(.01)\n", " while refdate.weekday() in (5,6) or refdate in holidays:\n", " refdate += timedelta(days=1) \n", " while n:\n", " refdate += timedelta(days=1)\n", " while refdate.weekday() in (5,6) or refdate in holidays:\n", " refdate += timedelta(days=1)\n", " n -= 1\n", " return refdate\n", "\n", "# July August September \n", "# Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa \n", "# 1 2 3 4 5 6 1 2 3 1 2 3 4 5 6 7 \n", "# 7 8 9 10 11 12 13 4 5 6 7 8 9 10 8 9 10 11 12 13 14 \n", "# 14 15 16 17 18 19 20 11 12 13 14 15 16 17 15 16 17 18 19 20 21 \n", "# 21 22 23 24 25 26 27 18 19 20 21 22 23 24 22 23 24 25 26 27 28 \n", "# 28 29 30 31 25 26 27 28 29 30 31 29 30 \n", "\n", "print next_business_day(date(2013, 8, 30))\n", "print next_business_day(date(2013, 9, 1))\n", "\n", "def next_business_days(refdate, n=10):\n", " next_days = [next_business_day(refdate)]\n", " for _ in xrange(n-1):\n", " next_days.append(next_business_day(ten_days[-1]))\n", " return next_days\n", "\n", "print next_business_days(date(2013, 1, 1), 10)\n", "% timeit next_business_days(date(2013, 1, 1), 90)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2013-09-03\n", "2013-09-04\n", "[datetime.date(2013, 1, 3), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17), datetime.date(2013, 9, 17)]" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "1 loops, best of 3: 916 ms per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 103 }, { "cell_type": "code", "collapsed": false, "input": [ "def next_business_days(refdate, holidays=set(holidays.values())): \n", " sleep(.01)\n", " while refdate.weekday() in (5,6) or refdate in holidays:\n", " refdate += timedelta(days=1) \n", " while True:\n", " refdate += timedelta(days=1)\n", " while refdate.weekday() in (5,6) or refdate in holidays:\n", " refdate += timedelta(days=1)\n", " yield refdate\n", "\n", "print list(islice(next_business_days(date(2013, 1, 1)), None, 10))\n", "% timeit list(islice(next_business_days(date(2013, 1, 1)), None, 90))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[datetime.date(2013, 1, 3), datetime.date(2013, 1, 4), datetime.date(2013, 1, 7), datetime.date(2013, 1, 8), datetime.date(2013, 1, 9), datetime.date(2013, 1, 10), datetime.date(2013, 1, 11), datetime.date(2013, 1, 14), datetime.date(2013, 1, 15), datetime.date(2013, 1, 16)]\n", "100 loops, best of 3: 10.4 ms per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 104 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "knobs and buttons and modalities" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from functools import wraps\n", "\n", "# messy\n", "def pumped(gen):\n", " @wraps(gen)\n", " def inner(*args, **kwargs):\n", " g = gen(*args, **kwargs)\n", " next(g)\n", " return g.send\n", " return inner" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "@pumped\n", "def predicate(x, state=0):\n", " value = yield\n", " while True:\n", " if state+value <= x: # take values until you exceed the maximum\n", " state += value\n", " value = yield True \n", " else:\n", " value = yield False\n", "\n", "from itertools import repeat, chain, takewhile\n", "greedy = lambda items, predicate: chain.from_iterable(takewhile(predicate,repeat(x)) for x in items)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "from __future__ import division, unicode_literals\n", "from itertools import groupby\n", "from random import randint\n", "\n", "denominations = [1,5,10,25,100,500,1000,2000]\n", "\n", "for _ in xrange(10):\n", " amount = randint(0,1000) # randomly pick a dollar amount\n", " pred = predicate(amount) # create the predicate\n", "\n", " coins = greedy(reversed(denominations), pred) # greedy algorithm\n", "\n", " # pretty print\n", " print 'your change for {:>5.2f}$ = {}'.format(amount/100, \n", " ' + '.join('{:>2d}\u00d7{:<3}'.format(sum(1 for _ in cs),\n", " (('{:d}\u00a2' if c < 100 else '{:.0f}$').format(c if c < 100 else c/100))) for c,cs in groupby(coins)))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "your change for 9.89$ = 1\u00d75$ + 4\u00d71$ + 3\u00d725\u00a2 + 1\u00d710\u00a2 + 4\u00d71\u00a2 \n", "your change for 0.10$ = 1\u00d710\u00a2\n", "your change for 8.52$ = 1\u00d75$ + 3\u00d71$ + 2\u00d725\u00a2 + 2\u00d71\u00a2 \n", "your change for 7.40$ = 1\u00d75$ + 2\u00d71$ + 1\u00d725\u00a2 + 1\u00d710\u00a2 + 1\u00d75\u00a2 \n", "your change for 6.57$ = 1\u00d75$ + 1\u00d71$ + 2\u00d725\u00a2 + 1\u00d75\u00a2 + 2\u00d71\u00a2 \n", "your change for 0.91$ = 3\u00d725\u00a2 + 1\u00d710\u00a2 + 1\u00d75\u00a2 + 1\u00d71\u00a2 \n", "your change for 0.74$ = 2\u00d725\u00a2 + 2\u00d710\u00a2 + 4\u00d71\u00a2 \n", "your change for 5.06$ = 1\u00d75$ + 1\u00d75\u00a2 + 1\u00d71\u00a2 \n", "your change for 9.25$ = 1\u00d75$ + 4\u00d71$ + 1\u00d725\u00a2\n", "your change for 2.91$ = 2\u00d71$ + 3\u00d725\u00a2 + 1\u00d710\u00a2 + 1\u00d75\u00a2 + 1\u00d71\u00a2 \n" ] } ], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [ "roman = { 1: 'i', 4: 'iv', 5: 'v', 9: 'ix', 10: 'x',\n", " 40: 'ix', 50: 'x', 90: 'xc', 100: 'c', 400: 'cd',\n", " 500: 'd', 900: 'cm', 1000: 'm',}\n", "\n", "for _ in xrange(10):\n", " year = randint(1900,2200) # randomly pick a year\n", " pred = predicate(year) # create the predicate\n", " \n", " numerals = greedy(reversed(sorted(roman)), pred) # greedy algorithm\n", " \n", " # pretty print\n", " print 'the year {} is written {}'.format( year,''.join(roman[x].upper() for x in list(numerals)))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "the year 2012 is written MMXII\n", "the year 2172 is written MMCXXXII\n", "the year 2129 is written MMCXXIX\n", "the year 1990 is written MCMXC\n", "the year 1907 is written MCMVII\n", "the year 2192 is written MMCXCII\n", "the year 1932 is written MCMXXXII\n", "the year 2173 is written MMCXXXIII\n", "the year 2097 is written MMXCVII\n", "the year 1989 is written MCMXXXXIX\n" ] } ], "prompt_number": 23 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "VII. Showcase" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "The showcase is one of the main attractions of `The Price is Right.`\n", "\n", "70+ games.\n", "\n", "Drew Carey has lost a lot of weight. Who remembers Bob Barker? \n", "\n", "The `Price is Right` is a global phenomenon: \u8cfc\u7269\u8857 (\u9ad8\u535a)\n", "\n", "Showcase is the last game; spin the wheel." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from itertools import repeat, izip, count, chain\n", "from random import randrange\n", "from time import sleep\n", "\n", "# helper function\n", "sleep = lambda n, sleep=sleep: lambda: sleep(n)\n", "\n", "randoms = (randrange(0,63) for _ in count())\n", "pauses = chain(repeat(sleep(0), 2500), repeat(sleep(0.01), 250), repeat(sleep(0.1), 25), repeat(sleep(1), 5))\n", "\n", "for pause, random in izip(pauses, randoms):\n", " pause()\n", " print random" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "raw", "metadata": {}, "source": [ "Lets add our own pseudo-random number generator." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# ref: en.wikipedia.org/wiki/Mersenne_twister\n", "def mersenne(seed = 1, period=397, length=624):\n", " state, tm = [seed & 0xffffffff], lambda op, x: x ^ op(x)\n", " for i in xrange(1,length):\n", " state.append((0x6c078965 * (state[-1] ^ (state[-1] >> 30)) + i) & 0xffffffff)\n", " while True:\n", " for i in xrange(length):\n", " y = (state[i] & 0x80000000) + (state[(i+1)%length] & 0x7fffffff)\n", " state[i] = (state[(i+period)%length] ^ (y >> 1)) ^ (0x9908b0df if y%2 else 0)\n", " for i in xrange(length):\n", " yield tm(lambda x: x >> 18, tm(lambda x: (x << 15) & 0xefc60000, tm(lambda x: (x << 7) & 0x9d2c5680, tm(lambda x: x >> 11, state[i]))))\n", " \n", "from itertools import takewhile\n", "def randrange(start, stop, mersenne=mersenne(seed=1)):\n", " size = 2**32 // (stop - start)\n", " return start + next(takewhile(lambda x: 0 <= x < (stop-start)*size,mersenne)) % (stop-start)\n", "\n", "m = mersenne()\n", "assert list(islice(m,0,10)) == [1791095845, 4282876139, 3093770124, 4005303368, 491263, 550290313, 1298508491, 4290846341, 630311759, 1013994432]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 153 }, { "cell_type": "raw", "metadata": {}, "source": [ "How can we better simulate the wheel?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from random import randrange\n", "\n", "class Wheel(object):\n", " def __init__(self, start=0, players=100):\n", " self.start = start\n", " self.players = players\n", " \n", " def spin(self):\n", " state = self.start\n", " for _ in xrange(randrange(100,200)):\n", " print '| {:>2f} |'.format(self.state)\n", " self.state = (self.state + 1) % players\n", " \n", " # ..." ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "raw", "metadata": {}, "source": [ "Can we simulate this more simply?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from __future__ import division\n", "from time import sleep\n", "from random import random\n", "\n", "forward, backward = lambda n: n+1, lambda n: n-1\n", "def wheel(iterable, state=0, direction=forward):\n", " values = list(iterable)\n", " while True:\n", " direction = (yield values[state]) or direction\n", " state = direction(state) % len(values)\n", "\n", "transition = lambda v,t: v-v/abs(v)*5*random()-abs(v)/(2+random())*t\n", "def spin(wheel, velocity=500, stop=0.25, transition=transition):\n", " next(wheel) # ugly\n", " while abs(velocity) > stop:\n", " yield wheel.send(forward if velocity > 0 else backward)\t\t\n", " sleep(1/abs(velocity))\n", " velocity = transition(velocity,1/velocity)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 38 }, { "cell_type": "raw", "metadata": {}, "source": [ "Notice that we have more control over the wheel." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def spin(wheel, velocity=500, stop=0.25, transition=transition):\n", "\tnext(wheel) # ugly\n", "\twhile abs(velocity) > stop:\n", "\t\tyield wheel.send(lambda n: n + int(velocity)) # <--\n", "\t\tsleep(1/abs(velocity))\n", "\t\tvelocity = transition(velocity,1/velocity)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 26 }, { "cell_type": "raw", "metadata": {}, "source": [ "Notice how easy it is to test." ] }, { "cell_type": "code", "collapsed": false, "input": [ "w = wheel([0,1,2])\n", "assert next(w) == 0\n", "assert next(w) == 1\n", "assert next(w) == 2\n", "assert next(w) == 0\n", "assert next(w) == 1\n", "\n", "w = wheel([0,1,2], direction=backward)\n", "assert next(w) == 0\n", "assert next(w) == 2\n", "assert next(w) == 1\n", "assert next(w) == 0\n", "assert next(w) == 2\n", "\n", "w = wheel([0,1,2], direction=lambda n: n+3)\n", "assert next(w) == 0\n", "assert next(w) == 0\n", "\n", "w, v = wheel([0,1,2]), wheel(xrange(3))\n", "assert next(w) == next(v)\n", "assert next(w) == next(v)\n", "\n", "w = wheel([0,1,2])\n", "% timeit list(spin(w, velocity=10, stop=10))\n", "% timeit list(spin(w, velocity=10, stop=0, transition=lambda v,t: v-5*v*t))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1000000 loops, best of 3: 1.17 us per loop\n", "1 loops, best of 3: 301 ms per loop" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 45 }, { "cell_type": "raw", "metadata": {}, "source": [ "We can further modularise this." ] }, { "cell_type": "code", "collapsed": false, "input": [ "friction = lambda v,t: v-v/abs(v)*5*random()-abs(v)/(2+random())*t\n", "def velocity(start=500, stop=0.25, friction=friction):\n", "\tstate = start\n", "\twhile abs(state) > stop:\n", "\t\tyield state\n", "\t\tstate = friction(state, 1/state)\n", "\n", "def spin(wheel, velocity):\n", "\tnext(wheel) # ugly\n", "\tfor vel in velocity:\n", "\t\tyield wheel.send(lambda n: n + int(vel))\n", "\t\tsleep(1/abs(vel))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 161 }, { "cell_type": "code", "collapsed": false, "input": [ "v = velocity(500, 0.25)\n", "assert next(v) > next(v)\n", "\n", "v = velocity(500, 0.25)\n", "assert list(v)\n", "\n", "v = velocity(500, 0.25)\n", "print list(v)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[500, 499.0817964316207, 496.7659122515505, 495.08552010237815, 491.282387088325, 487.93842180536495, 484.19405001694713, 482.0057844732008, 478.7238688452039, 475.5032114360953, 471.7675016676754, 469.8864501437916, 466.2870622381248, 464.83320557959144, 460.15425099202787, 456.00283619126964, 451.76537550458596, 449.44247485720877, 445.5739938836977, 443.8688028914643, 443.325138533312, 442.82904870257494, 441.573631315599, 439.8352065176586, 436.94307003243193, 434.56333918383905, 431.1159779876828, 428.1545743352637, 423.28181795374263, 420.5611098275818, 417.40925406234214, 414.4591870065937, 411.69219033962656, 408.7512452534986, 407.83220138412423, 406.46865706447596, 401.7756579653891, 396.7108031076217, 394.170516421267, 391.96703747194175, 391.14707228105, 388.7501117908976, 386.27118072215046, 383.7167324660817, 378.7833303992562, 373.75069101453533, 372.46980539238854, 369.9234513315834, 366.1096856671547, 364.20210560769794, 362.3976165089374, 359.0982179794059, 355.1211082334828, 353.80910869541975, 350.5842100128526, 349.71959531563124, 347.4153776039645, 346.23949269226483, 342.2879433016071, 338.3870290850201, 337.69996339837417, 333.46246641050396, 330.7195703326987, 328.74298200804674, 323.73148763236213, 322.9350618404671, 321.50542524013883, 318.00531062434254, 312.78912037261307, 309.647363266313, 307.0125075672744, 302.8325850039156, 297.5424573016874, 295.03958576192764, 293.80615443507736, 292.9430656464813, 291.49572805467665, 286.8501542297024, 282.15802579958404, 278.42359894762967, 276.4002892182105, 273.1661480124695, 269.5892064459307, 266.29859379573486, 264.40349547795034, 260.51177311272176, 256.12510786022915, 250.839432935257, 250.31090838268625, 245.86669039857406, 241.1075028644655, 239.09201197791702, 234.98520989686176, 233.710311945322, 231.1764567996815, 226.85486446455076, 224.33052547781725, 222.02378340970938, 220.14326829387144, 216.27894192326022, 213.1725406367333, 209.04975184292624, 205.48271789189957, 203.86217350447987, 200.00882850245154, 199.44886903332224, 198.3552806126174, 194.5012476067534, 191.15447739869526, 187.96570344222883, 183.83655030916793, 179.08611446749487, 174.15381040273087, 170.42673599855806, 167.69726753382565, 162.46211068150646, 160.21851704250344, 155.43863201051002, 154.5082199179937, 149.94752380647537, 148.41710951581513, 147.49207850633084, 145.88619185925617, 140.8416525561992, 139.81195314947087, 135.6007287434456, 130.80348490620517, 129.5140589596599, 129.04567776925992, 127.84644885358462, 125.67759942246292, 124.24685276928172, 119.79599230876926, 118.81323602189435, 118.00389009146554, 117.28552955566607, 114.37531199507367, 111.54099257368635, 109.27078291882988, 105.12798596501703, 102.7552346803562, 99.90479577436477, 97.62957499202311, 94.83351178598595, 90.61025732397695, 86.42644343625584, 83.44703389761457, 82.04680513629611, 78.22340649000053, 75.78900274645054, 73.24509816475968, 71.81252408317644, 69.07134255317911, 67.06764269403341, 64.12557842590694, 62.25526449444695, 58.185535596252734, 53.25096015345708, 50.01623638424963, 45.21374690677783, 42.20997207866244, 40.02867570300589, 34.64041753783563, 34.03253790830072, 29.017420898377953, 28.086514851300553, 25.76920462146157, 21.232521445238767, 16.93779084404379, 14.986564436514094, 10.503979648158625, 7.967383833679981, 6.2877142369347325, 2.8718434777339663, 1.8450054139716494, -2.4157473566898378, 2.2611475223068744, -1.1143165268282922, 0.2625693314053857, -3.815865511492414, 0.7030720821363874, -3.2367212976233937, -1.4588499894114804, 1.0872610466296941, -0.4092751853535173, 3.813448600861101, 1.4590528069405848, 0.7340765522835442, -2.1093497629134537, 3.006970624175923, 1.8369818179220516, 0.2776043233310767, -0.5968984314029906, 4.76530376422617, 2.01106324288153, 0.7107035608560084, -2.6214121637054304, -0.76157451582592, 3.737767438416472, 3.2149405855890194, 2.1945749324327033, 1.5692558741721352]\n" ] } ], "prompt_number": 170 }, { "cell_type": "raw", "metadata": {}, "source": [ "All together..." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from __future__ import division\n", "from time import sleep\n", "from random import random\n", "\n", "forward, backward = lambda n: n+1, lambda n: n-1\n", "def wheel(iterable, state=0, direction=forward):\n", "\tvalues = list(iterable)\n", "\twhile True:\n", "\t\tdirection = (yield values[state]) or direction\n", "\t\tstate = direction(state) % len(values)\n", "\n", "friction = lambda v,t: v-v/abs(v)*5*random()-abs(v)/(2+random())*t\n", "def velocity(start=500, stop=0.25, friction=friction):\n", "\tstate = start\n", "\twhile abs(state) > stop:\n", "\t\tyield state\n", "\t\tstate = friction(state, 1/state)\n", "\n", "def spin(wheel, velocity):\n", "\tnext(wheel) # ugly\n", "\tfor vel in velocity:\n", "\t\tyield wheel.send(lambda n: n + int(vel))\n", "\t\tsleep(1/abs(vel))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 173 }, { "cell_type": "code", "collapsed": false, "input": [ "from random import randrange, shuffle\n", "\n", "players, prizes = range(25), ['book'] + ['t-shirt']*5 + ['mug']*5\n", "winners = [(player, prize) for player in players for prize in prizes]\n", "shuffle(winners)\n", "\n", "state, velocity = randrange(0, len(winners)), velocity(randrange(500, 750))\n", "\n", "for number, prize in spin(wheel(winners, state=state), velocity=velocity):\n", " print '| {:>2} {:<{}} |'.format(number, prize, max(len(p) for p in prizes))\n", "\n", "print 'you won a ... {}, #{}'.format(prize, number)\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "| 3 mug |\n", "| 16 t-shirt |\n", "| 2 mug |\n", "| 9 mug |\n", "| 16 mug |\n", "| 21 t-shirt |\n", "| 16 book |\n", "| 11 t-shirt |\n", "| 9 mug |\n", "| 13 t-shirt |\n", "| 8 t-shirt |\n", "| 21 mug |\n", "| 15 mug |\n", "| 11 t-shirt |\n", "| 19 t-shirt |\n", "| 8 mug |\n", "| 18 mug |\n", "| 9 t-shirt |\n", "| 10 mug |\n", "| 11 t-shirt |\n", "| 0 mug |\n", "| 10 t-shirt |\n", "| 4 mug |\n", "| 1 mug |\n", "| 20 t-shirt |\n", "| 1 mug |\n", "| 18 t-shirt |\n", "| 17 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 11 mug |\n", "| 2 t-shirt |\n", "| 11 t-shirt |\n", "| 24 t-shirt |\n", "| 14 mug |\n", "| 23 t-shirt |\n", "| 18 mug |\n", "| 11 mug |\n", "| 4 t-shirt |\n", "| 4 mug |\n", "| 22 t-shirt |\n", "| 18 t-shirt |\n", "| 11 mug |\n", "| 18 t-shirt |\n", "| 3 t-shirt |\n", "| 17 t-shirt |\n", "| 24 t-shirt |\n", "| 18 mug |\n", "| 1 mug |\n", "| 9 t-shirt |\n", "| 18 t-shirt |\n", "| 20 t-shirt |\n", "| 23 t-shirt |\n", "| 11 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 17 mug |\n", "| 22 book |\n", "| 15 mug |\n", "| 24 t-shirt |\n", "| 22 book |\n", "| 9 t-shirt |\n", "| 22 mug |\n", "| 15 mug |\n", "| 20 mug |\n", "| 5 t-shirt |\n", "| 10 mug |\n", "| 21 t-shirt |\n", "| 9 mug |\n", "| 1 t-shirt |\n", "| 15 mug |\n", "| 18 book |\n", "| 13 mug |\n", "| 14 mug |\n", "| 13 mug |\n", "| 3 mug |\n", "| 16 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 21 t-shirt |\n", "| 4 mug |\n", "| 22 t-shirt |\n", "| 4 mug |\n", "| 17 mug |\n", "| 11 t-shirt |\n", "| 10 book |\n", "| 9 t-shirt |\n", "| 0 t-shirt |\n", "| 23 t-shirt |\n", "| 11 t-shirt |\n", "| 8 mug |\n", "| 15 mug |\n", "| 0 mug |\n", "| 1 book |\n", "| 15 t-shirt |\n", "| 22 mug |\n", "| 8 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 11 mug |\n", "| 12 mug |\n", "| 24 book |\n", "| 18 t-shirt |\n", "| 14 mug |\n", "| 18 mug |\n", "| 2 t-shirt |\n", "| 5 mug |\n", "| 23 t-shirt |\n", "| 24 t-shirt |\n", "| 4 t-shirt |\n", "| 23 mug |\n", "| 7 mug |\n", "| 7 t-shirt |\n", "| 15 book |\n", "| 7 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 23 t-shirt |\n", "| 18 mug |\n", "| 22 mug |\n", "| 21 t-shirt |\n", "| 20 t-shirt |\n", "| 16 t-shirt |\n", "| 7 mug |\n", "| 19 t-shirt |\n", "| 15 mug |\n", "| 1 book |\n", "| 10 book |\n", "| 12 mug |\n", "| 1 book |\n", "| 20 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 1 mug |\n", "| 12 t-shirt |\n", "| 0 t-shirt |\n", "| 23 mug |\n", "| 0 mug |\n", "| 24 mug |\n", "| 17 mug |\n", "| 2 book |\n", "| 5 t-shirt |\n", "| 7 t-shirt |\n", "| 21 mug |\n", "| 9 book |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 19 t-shirt |\n", "| 7 mug |\n", "| 5 mug |\n", "| 20 t-shirt |\n", "| 8 mug |\n", "| 19 book |\n", "| 24 t-shirt |\n", "| 2 mug |\n", "| 14 mug |\n", "| 24 book |\n", "| 19 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 14 t-shirt |\n", "| 21 mug |\n", "| 2 t-shirt |\n", "| 6 t-shirt |\n", "| 3 mug |\n", "| 9 mug |\n", "| 14 t-shirt |\n", "| 11 t-shirt |\n", "| 4 mug |\n", "| 18 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 12 t-shirt |\n", "| 3 t-shirt |\n", "| 17 mug |\n", "| 23 t-shirt |\n", "| 1 t-shirt |\n", "| 11 mug |\n", "| 11 t-shirt |\n", "| 18 t-shirt |\n", "| 9 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 19 mug |\n", "| 21 t-shirt |\n", "| 5 mug |\n", "| 19 book |\n", "| 23 t-shirt |\n", "| 6 mug |\n", "| 15 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 4 t-shirt |\n", "| 10 book |\n", "| 13 t-shirt |\n", "| 9 mug |\n", "| 14 mug |\n", "| 6 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 17 t-shirt |\n", "| 6 mug |\n", "| 10 t-shirt |\n", "| 15 t-shirt |\n", "| 3 mug |\n", "| 12 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 8 book |\n", "| 5 t-shirt |\n", "| 9 mug |\n", "| 13 mug |\n", "| 17 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 4 mug |\n", "| 12 mug |\n", "| 19 mug |\n", "| 7 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 4 mug |\n", "| 21 book |\n", "| 24 mug |\n", "| 18 book |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 4 t-shirt |\n", "| 4 mug |\n", "| 12 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 7 t-shirt |\n", "| 3 t-shirt |\n", "| 1 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 6 mug |\n", "| 13 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 9 t-shirt |\n", "| 24 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 13 t-shirt |\n", "| 21 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 14 mug |\n", "| 13 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 10 t-shirt |\n", "| 11 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 17 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 1 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 16 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 21 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 21 t-shirt |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 16 mug |" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n", "| 2 book |" ] }, { "ename": "StdinNotImplementedError", "evalue": "raw_input was called, but this frontend does not support stdin.", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mStdinNotImplementedError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mnumber\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mprize\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mspin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mwheel\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mwinners\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstate\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mstate\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvelocity\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mvelocity\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[1;32mprint\u001b[0m \u001b[1;34m'| {:>2} {:<{}} |'\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnumber\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mprize\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmax\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mp\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mprizes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mraw_input\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'you won a ... {}, #{}'\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprize\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mnumber\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/home/powell/scratch/ipython/local/lib/python2.7/site-packages/IPython/zmq/ipkernel.pyc\u001b[0m in \u001b[0;36m\u001b[1;34m(prompt)\u001b[0m\n\u001b[0;32m 343\u001b[0m \u001b[0mraw_input\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mlambda\u001b[0m \u001b[0mprompt\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m''\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_raw_input\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mprompt\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mident\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparent\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 344\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 345\u001b[1;33m \u001b[0mraw_input\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mlambda\u001b[0m \u001b[0mprompt\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m''\u001b[0m \u001b[1;33m:\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_no_raw_input\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 346\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 347\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mpy3compat\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mPY3\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m/home/powell/scratch/ipython/local/lib/python2.7/site-packages/IPython/zmq/ipkernel.pyc\u001b[0m in \u001b[0;36m_no_raw_input\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 698\u001b[0m \"\"\"Raise StdinNotImplentedError if active frontend doesn't support\n\u001b[0;32m 699\u001b[0m stdin.\"\"\"\n\u001b[1;32m--> 700\u001b[1;33m raise StdinNotImplementedError(\"raw_input was called, but this \"\n\u001b[0m\u001b[0;32m 701\u001b[0m \"frontend does not support stdin.\") \n\u001b[0;32m 702\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mStdinNotImplementedError\u001b[0m: raw_input was called, but this frontend does not support stdin." ] }, { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 174 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "VIII. Sign-Off" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "\u2018James Powell, reminding you to help control the pet population." ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "\u2018Remember to spay and neuter your pets!\u2019" ] } ], "metadata": {} } ] }