Skip to content

Instantly share code, notes, and snippets.

@sparkiegeek
Last active December 12, 2015 03:28
Show Gist options
  • Select an option

  • Save sparkiegeek/4706674 to your computer and use it in GitHub Desktop.

Select an option

Save sparkiegeek/4706674 to your computer and use it in GitHub Desktop.
Advanced Python Tutorial from PyGround, Timisoara - Feb 2013
{
"metadata": {
"name": "Advanced Python Programming"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Who am I?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Adam Collard [@acollard](http://twitter.com/acollard)\n",
"\n",
"Sofware Architect at Cmed Technology"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Topics"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Functional programming\n",
"* Iterators and generators"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"What is Functional Programming?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def one():\n",
" \"\"\"It's 42/42\"\"\"\n",
" return 1\n",
"\n",
"def incrementer(function):\n",
" \"\"\"Adds one to the result of the given function\"\"\"\n",
" return function() + 1"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"incrementer(one)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 3,
"text": [
"2"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def multiplier(function, times=5):\n",
" \"\"\"Multiplies result of given function by <times> times, default 5\"\"\"\n",
" return function() * times"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"multiplier(one)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 5,
"text": [
"5"
]
}
],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"map(int, [\"1\", \"0\", \"2\", \"25\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 6,
"text": [
"[1, 0, 2, 25]"
]
}
],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"filter(lambda x: x % 2 == 0, range(5))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 7,
"text": [
"[0, 2, 4]"
]
}
],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Functions are first class objects in Python!\n",
"\n",
" - Can be passed to other functions\n",
" - Can be stored in lists, dictionaries, ...\n",
" - Have attributes"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"doers = [multiplier, incrementer]\n",
"\n",
"for function in doers:\n",
" print function.__name__, \"=\", function(one)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"multiplier = 5\n",
"incrementer = 2\n"
]
}
],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"multiplier.__doc__"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 9,
"text": [
"'Multiplies result of given function by <times> times, default 5'"
]
}
],
"prompt_number": 9
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Why should I care?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Functional programming offers several benefits:\n",
"\n",
"* Clean design\n",
"* Composable\n",
"* Simple\n",
"* Easily testable\n",
"* Easily scalable"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%load_ext ipython_nose"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def only_evens(a_list):\n",
" return [x for x in a_list if x % 2 == 0]\n",
"\n",
"def test_empty_list():\n",
" \"\"\"Test empty list is empty\"\"\"\n",
" assert only_evens([]) == []\n",
" \n",
"def test_single_even_element():\n",
" \"\"\"Test with single element\"\"\"\n",
" assert only_evens([2]) == [2]\n",
" \n",
"def test_odds_filtered():\n",
" \"\"\"Test we odd numbers not included\"\"\"\n",
" assert only_evens([1, 2, 3, 4]) == [2, 4]\n",
" \n",
"def test_zero_included():\n",
" \"\"\"Test 0 is counted as even\"\"\"\n",
" assert only_evens([0, 1, 2, 3]) == [0, 2]\n",
"\n",
"#import unittest\n",
"#class OnlyEvensTest(unittest.TestCase):\n",
"# \n",
"# def test_foo(self):\n",
"# self.assertFalse()\n",
"\n"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"# This is IPython magic..\n",
"%nose"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<div id=\"ipython_nose_aefb48046ca54c7b931b96e1d9511d87\"></div>"
],
"output_type": "display_data"
},
{
"javascript": [
"document.ipython_nose_aefb48046ca54c7b931b96e1d9511d87 = $(\"#ipython_nose_aefb48046ca54c7b931b96e1d9511d87\");"
],
"output_type": "display_data"
},
{
"javascript": [
"document.ipython_nose_aefb48046ca54c7b931b96e1d9511d87.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
"document.ipython_nose_aefb48046ca54c7b931b96e1d9511d87.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
"document.ipython_nose_aefb48046ca54c7b931b96e1d9511d87.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
"document.ipython_nose_aefb48046ca54c7b931b96e1d9511d87.append($(\"<span>.</span>\"));"
],
"output_type": "display_data"
},
{
"javascript": [
"delete document.ipython_nose_aefb48046ca54c7b931b96e1d9511d87;"
],
"output_type": "display_data"
},
{
"html": [
" <style type=\"text/css\">\n",
" span.nosefailedfunc {\n",
" font-family: monospace;\n",
" font-weight: bold;\n",
" }\n",
" div.noseresults {\n",
" width: 100%;\n",
" }\n",
" div.nosebar {\n",
" float: left;\n",
" padding: 1ex 0px 1ex 0px;\n",
" }\n",
" div.nosebar.fail {\n",
" background: #ff3019; /* Old browsers */\n",
" /* FF3.6+ */\n",
" background: -moz-linear-gradient(top, #ff3019 0%, #cf0404 100%);\n",
" /* Chrome,Safari4+ */\n",
" background: -webkit-gradient(linear, left top, left bottom,\n",
" color-stop(0%,#ff3019),\n",
" color-stop(100%,#cf0404));\n",
" /* Chrome10+,Safari5.1+ */\n",
" background: -webkit-linear-gradient(top, #ff3019 0%,#cf0404 100%);\n",
" /* Opera 11.10+ */\n",
" background: -o-linear-gradient(top, #ff3019 0%,#cf0404 100%);\n",
" /* IE10+ */\n",
" background: -ms-linear-gradient(top, #ff3019 0%,#cf0404 100%);\n",
" /* W3C */\n",
" background: linear-gradient(to bottom, #ff3019 0%,#cf0404 100%);\n",
" }\n",
" div.nosebar.pass {\n",
" background: #52b152;\n",
" background: -moz-linear-gradient(top, #52b152 1%, #008a00 100%);\n",
" background: -webkit-gradient(linear, left top, left bottom,\n",
" color-stop(1%,#52b152),\n",
" color-stop(100%,#008a00));\n",
" background: -webkit-linear-gradient(top, #52b152 1%,#008a00 100%);\n",
" background: -o-linear-gradient(top, #52b152 1%,#008a00 100%);\n",
" background: -ms-linear-gradient(top, #52b152 1%,#008a00 100%);\n",
" background: linear-gradient(to bottom, #52b152 1%,#008a00 100%);\n",
" }\n",
" div.nosebar.skip {\n",
" background: #f1e767;\n",
" background: -moz-linear-gradient(top, #f1e767 0%, #feb645 100%);\n",
" background: -webkit-gradient(linear, left top, left bottom,\n",
" color-stop(0%,#f1e767),\n",
" color-stop(100%,#feb645));\n",
" background: -webkit-linear-gradient(top, #f1e767 0%,#feb645 100%);\n",
" background: -o-linear-gradient(top, #f1e767 0%,#feb645 100%);\n",
" background: -ms-linear-gradient(top, #f1e767 0%,#feb645 100%);\n",
" background: linear-gradient(to bottom, #f1e767 0%,#feb645 100%);\n",
" }\n",
" div.nosebar.leftmost {\n",
" border-radius: 4px 0 0 4px;\n",
" }\n",
" div.nosebar.rightmost {\n",
" border-radius: 0 4px 4px 0;\n",
" }\n",
" div.nosefailbanner {\n",
" border-radius: 4px 0 0 4px;\n",
" border-left: 10px solid #cf0404;\n",
" padding: 0.5ex 0em 0.5ex 1em;\n",
" margin-top: 1ex;\n",
" margin-bottom: 0px;\n",
" }\n",
" div.nosefailbanner.expanded {\n",
" border-radius: 4px 4px 0 0;\n",
" border-top: 10px solid #cf0404;\n",
" }\n",
" pre.nosetraceback {\n",
" border-radius: 0 4px 4px 4px;\n",
" border-left: 10px solid #cf0404;\n",
" padding: 1em;\n",
" margin-left: 0px;\n",
" margin-top: 0px;\n",
" display: none;\n",
" }\n",
" </style>\n",
" \n",
" <script>\n",
" setTimeout(function () {\n",
" $('.nosefailtoggle').bind(\n",
" 'click',\n",
" function () {\n",
" $(\n",
" $(this)\n",
" .parent().toggleClass('expanded')\n",
" .parent()\n",
" .children()\n",
" .filter('.nosetraceback')\n",
" ).toggle();\n",
" }\n",
" );},\n",
" 0);\n",
" </script>\n",
" \n",
" <div class=\"noseresults\">\n",
" <div class=\"nosebar fail leftmost\" style=\"width: 0%\">\n",
" &nbsp;\n",
" </div>\n",
" <div class=\"nosebar skip\" style=\"width: 0%\">\n",
" &nbsp;\n",
" </div>\n",
" <div class=\"nosebar pass rightmost\" style=\"width: 100%\">\n",
" &nbsp;\n",
" </div>\n",
" 4/4 tests passed\n",
" </div>\n",
" "
],
"output_type": "pyout",
"prompt_number": 5,
"text": [
"4/4 tests passed\n"
]
}
],
"prompt_number": 5
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"What are the techniques?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* small functions\n",
"* docstrings\n",
"* no mutable arguments\n",
"* *avoid* side-effects\n",
"* *args and **kwargs if you don't care\n",
"* @decorators"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def log_result_of(function):\n",
" \"\"\"Logs the result of the given function\"\"\"\n",
" def inner(*args, **kwargs):\n",
" result = function(*args, **kwargs)\n",
" kwargs_repr = \", \".join(\"%s=%s\" % (k, repr(v)) for k, v in kwargs.iteritems())\n",
" print \"LOG: %s(%s, %s) -> %s\" % (function.__name__, \", \".join(repr(x) for x in args), kwargs_repr, result)\n",
" return result\n",
"\n",
" return inner\n",
"\n",
"@log_result_of\n",
"def indent(s):\n",
" return \" %s\" % s\n",
"\n",
"\n",
"\n",
"x = indent(\"foo\")\n",
"\n",
"print \"x is %s\" % repr(x)\n",
"\n",
"\n",
"\", \".join([\"a\",\"b\", \"c\", \"d\"])\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"LOG: indent('foo', ) -> foo\n",
"x is ' foo'\n"
]
},
{
"output_type": "pyout",
"prompt_number": 34,
"text": [
"'a, b, c, d'"
]
}
],
"prompt_number": 34
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"What can help me in the standard library?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import functools"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**functools.partial**\n"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def foo(bar, baz):\n",
" print \"Bar\", bar\n",
" print \"Baz\", baz\n",
" print\n",
" \n",
"fixed_bar = functools.partial(foo, \"2\")\n",
"\n",
"fixed_bar(3)\n",
"fixed_bar(baz=\"baz\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Bar 2\n",
"Baz 3\n",
"\n",
"Bar 2\n",
"Baz baz\n",
"\n"
]
}
],
"prompt_number": 14
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**functools.wraps**"
]
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"def wraps(fn):\n",
" fn.call_count = 0\n",
" @functools.wraps(fn)\n",
" def inner(*args, **kwargs):\n",
" \"\"\"Count number of calls\"\"\"\n",
" fn.call_count += 1\n",
" return fn(*args, **kwargs)\n",
" return inner\n",
"\n",
"@wraps\n",
"def foo():\n",
" \"\"\"Prints foo\"\"\"\n",
" print \"foo\"\n",
"\n",
"foo()\n",
"foo()\n",
"print \"Foo doc\", foo.__doc__\n",
"print \"Foo func_name\", foo.func_name"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"foo\n",
"foo\n",
"Foo doc Prints foo\n",
"Foo func_name foo\n"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def unwrapped(fn):\n",
" fn.call_count = 0\n",
" def inner(*args, **kwargs):\n",
" \"\"\"Count number of calls\"\"\"\n",
" fn.call_count += 1\n",
" return fn(*args, **kwargs)\n",
" return inner\n",
" \n",
"@unwrapped\n",
"def bar():\n",
" \"\"\"Prints bar\"\"\"\n",
" print \"bar\"\n",
" \n",
"bar()\n",
"bar()\n",
"print \"Bar doc\", bar.__doc__\n",
"print \"Bar func_name\", bar.func_name"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"bar\n",
"bar\n",
"Bar doc Count number of calls\n",
"Bar func_name inner\n"
]
}
],
"prompt_number": 16
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**operator**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"map(operator.truth, [0, 1, None, []])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 25,
"text": [
"[False, True, False, False]"
]
}
],
"prompt_number": 25
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"operator.add -> x + y\n",
"\n",
"operator.mul -> x * y"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Iterators and generators"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"class Integers(object):\n",
" \n",
" def __init__(self, start=0, stop=10):\n",
" self.num = start\n",
" self.stop = stop\n",
"\n",
" def __iter__(self):\n",
" return self\n",
"\n",
" def next(self):\n",
" if self.num >= self.stop:\n",
" raise StopIteration()\n",
" self.num += 1\n",
" return self.num\n",
"\n",
"ints = Integers()\n",
"print list(ints)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n"
]
}
],
"prompt_number": 17
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for i in Integers(stop=3):\n",
" print i"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n",
"2\n",
"3\n"
]
}
],
"prompt_number": 42
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"my_range = iter(range(3))\n",
"next(my_range)\n",
"next(my_range)\n",
"next(my_range)\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 18,
"text": [
"2"
]
}
],
"prompt_number": 18
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"next(my_range)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "StopIteration",
"evalue": "",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-19-a0befe2dff4b>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmy_range\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mStopIteration\u001b[0m: "
]
}
],
"prompt_number": 19
},
{
"cell_type": "heading",
"level": 3,
"metadata": {},
"source": [
"Generators"
]
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"def generate_numbers(start=0, stop=10):\n",
" num = start\n",
" while num < stop:\n",
" num += 1\n",
" yield num\n",
" if num ==2:\n",
" return\n",
"\n",
"x = generate_numbers()\n",
"\n",
"list(x)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 7,
"text": [
"[1, 2]"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_generator = generate_numbers(stop=3)\n",
"next(my_generator)\n",
"next(my_generator)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 9,
"text": [
"2"
]
}
],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"next(my_generator)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "StopIteration",
"evalue": "",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mStopIteration\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-10-40133e33514d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmy_generator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mStopIteration\u001b[0m: "
]
}
],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def numbers_with_offset(start=0, stop=10):\n",
" num = start\n",
" while num < stop:\n",
" num += 1\n",
" offset = (yield num)\n",
" if offset:\n",
" num += offset\n",
"\n",
"print list(numbers_with_offset())"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n"
]
}
],
"prompt_number": 27
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_generator = numbers_with_offset()\n",
"for i in my_generator:\n",
" print i\n",
" if i == 3:\n",
" print my_generator.send(5)\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n",
"2\n",
"3\n",
"9\n",
"10\n"
]
}
],
"prompt_number": 28
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def fibonacci():\n",
" num = 1\n",
" previous = 0\n",
" while True:\n",
" yield num\n",
" next_num = num + previous\n",
" previous = num\n",
" num = next_num\n",
"\n",
"fibber = fibonacci()\n",
"next(fibber), next(fibber), next(fibber), next(fibber), next(fibber)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 30,
"text": [
"(1, 1, 2, 3, 5)"
]
}
],
"prompt_number": 30
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"List comprehension"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"[x for x in range(5)]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 35,
"text": [
"[0, 1, 2, 3, 4]"
]
}
],
"prompt_number": 35
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generator expression"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"(x for x in range(5))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 36,
"text": [
"<generator object <genexpr> at 0x323faf0>"
]
}
],
"prompt_number": 36
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 37,
"text": [
"[]"
]
}
],
"prompt_number": 37
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"... generator expressions can be used wherever we have ()s - no need for extra ones!"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list(x for x in range(5))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 38,
"text": [
"[0, 1, 2, 3, 4]"
]
}
],
"prompt_number": 38
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nested functions and closures\n",
"-----------------------------"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def foo():\n",
" a = 1\n",
" b = 2\n",
" def bar():\n",
" return a\n",
" return bar\n",
"\n",
"foo()()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 39,
"text": [
"1"
]
}
],
"prompt_number": 39
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What happens if we form a closure over mutable variables.."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def foo():\n",
" a = []\n",
" b = 2\n",
" def bar():\n",
" a.append(1)\n",
" return a\n",
" return bar"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 40
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"foo()()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 41,
"text": [
"[1]"
]
}
],
"prompt_number": 41
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"b = foo()\n",
"b()\n",
"b()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 42,
"text": [
"[1, 1]"
]
}
],
"prompt_number": 42
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"b()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 43,
"text": [
"[1, 1, 1]"
]
}
],
"prompt_number": 43
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"b()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "pyout",
"prompt_number": 44,
"text": [
"[1, 1, 1, 1]"
]
}
],
"prompt_number": 44
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment