{ "metadata": { "name": "dojo-20130607" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "raw", "metadata": {}, "source": [ "dojo-20130607\n", "nested generators\n", "tuple unpacking" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's the old style generator that did everything in one generator." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_even_fibonacci(last):\n", " a = 0\n", " b = 1\n", " while True:\n", " c = a + b\n", " a = b\n", " b = c\n", " if b > last:\n", " break\n", " if b % 2 == 0:\n", " yield b" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "[i for i in gen_even_fibonacci(1000)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 2, "text": [ "[2, 8, 34, 144, 610]" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's be more modular with more generators, where each generator does one thing well, and they can be combined with other generators. Each one is simple and easy to understand. This is like the Unix philosophy. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_fibonacci():\n", " a, b = 0, 1\n", " while True:\n", " a, b = b, a + b\n", " yield b" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_even(gen):\n", " for i in gen:\n", " if i % 2 == 0:\n", " yield i\n", " " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_lte(gen, n):\n", " for i in gen:\n", " if i > n:\n", " break\n", " yield i" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we get to the benefit. We can combine generators much like one combines Linux shell commands with pipes on the command line." ] }, { "cell_type": "code", "collapsed": false, "input": [ "[i for i in gen_lte(gen_even(gen_fibonacci()), 1000)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 6, "text": [ "[2, 8, 34, 144, 610]" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "[i for i in gen_lte(gen_fibonacci(), 1000)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 7, "text": [ "[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "evens = (i for i in gen_fibonacci() if i%2 == 0)\n", "[i for i in gen_lte(evens, 1000)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 8, "text": [ "[2, 8, 34, 144, 610]" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "evens = gen_even(gen_fibonacci())\n", "[i for i in gen_lte(evens, 1000)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 9, "text": [ "[2, 8, 34, 144, 610]" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "[i for i in gen_lte(gen_even(gen_fibonacci()), 1000)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 10, "text": [ "[2, 8, 34, 144, 610]" ] } ], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's easy to create new generators that can be combined with others." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def gen_n(gen, n):\n", " for i in gen:\n", " if n <= 0:\n", " break\n", " yield i\n", " n -= 1" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "[i for i in gen_n(gen_fibonacci(), 10)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 12, "text": [ "[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]" ] } ], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "[i for i in gen_n(gen_even(gen_fibonacci()), 10)]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 13, "text": [ "[2, 8, 34, 144, 610, 2584, 10946, 46368, 196418, 832040]" ] } ], "prompt_number": 13 }, { "cell_type": "raw", "metadata": {}, "source": [ "dabeaz: Daved M. Beazley\n", "Generator Tricks for Systems Programmers - Version 2.0\n", "http://www.dabeaz.com/generators-uk/index.html\n", "nested generators\n", "use like pipes" ] }, { "cell_type": "code", "collapsed": false, "input": [ "fibs = gen_fibonacci()\n", "evens = gen_even(fibs)\n", "lte = gen_lte(evens, 100)\n", "[i for i in lte]\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 14, "text": [ "[2, 8, 34]" ] } ], "prompt_number": 14 } ], "metadata": {} } ] }