Skip to content

Instantly share code, notes, and snippets.

@anandology
Last active December 28, 2015 06:59
Show Gist options
  • Save anandology/7460837 to your computer and use it in GitHub Desktop.
Save anandology/7460837 to your computer and use it in GitHub Desktop.
Advanced Python Workshop - Nov 2013 http://advancedpython.hasgeek.com/
Notes from Advanced Python Workshop by Anand Chitipothu conducted on Nov 14-16, 2013
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Advanced Python Workshop - Day 1\n",
"Nov 14, 2013<br/>\n",
"http://advancedpython.hasgeek.com/"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def square(x):\n",
" return x*x\n",
"\n",
"print square(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"16\n"
]
}
],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = square"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"text": [
"<function __main__.square>"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"square"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"text": [
"<function __main__.square>"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 5,
"text": [
"16"
]
}
],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def sum_of_squares(x, y):\n",
" return square(x) + square(y)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sum_of_squares(3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 7,
"text": [
"25"
]
}
],
"prompt_number": 7
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def cube(x): return x*x*x"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def sum_of_cubes(x, y):\n",
" return cube(x) + cube(y)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sum_of_cubes(3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 10,
"text": [
"91"
]
}
],
"prompt_number": 10
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def fxy(f, x, y):\n",
" return f(x) + f(y)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fxy(square, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 12,
"text": [
"25"
]
}
],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fxy(cube, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 13,
"text": [
"91"
]
}
],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a function `diff_of` that takes a function `f` and two numbers x, y as arguments and returns the difference of `f(x)` and `f(y)`."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def pow2(x): return 2**x"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fxy(pow2, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 15,
"text": [
"24"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# to compute square of 3+4, we can do:\n",
"a = 3 + 4\n",
"square(a)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 20,
"text": [
"49"
]
}
],
"prompt_number": 20
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# or \n",
"square(3+4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 22,
"text": [
"49"
]
}
],
"prompt_number": 22
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"can we do the samething with functions?\n",
"\n",
" fxy(<function defination here>, 3, 4)\n",
" \n",
"Python provides lambda expressions for doing that."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fxy(lambda x: 2**x, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 24,
"text": [
"24"
]
}
],
"prompt_number": 24
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fxy(lambda x: 4**x, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 25,
"text": [
"320"
]
}
],
"prompt_number": 25
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"def is a statement and lamdba is an expression.\n",
"\n",
"You can have only one expression in the body of lambda. Thats the limitation."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = lambda x: 2**x\n",
"print f(10)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1024\n"
]
}
],
"prompt_number": 26
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Built-in functions that take functions as arguments"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sorted([\"perl\", \"Python\", \"Java\", \"haskell\", \"c\", \"go\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 30,
"text": [
"['Java', 'Python', 'c', 'go', 'haskell', 'perl']"
]
}
],
"prompt_number": 30
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How do I sort these by length of the value instead of the value it self?\n",
"\n",
"The `sorted` function takes an optional argument `key`."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sorted([\"perl\", \"Python\", \"Java\", \"haskell\", \"c\", \"go\"], key=len)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 31,
"text": [
"['c', 'go', 'perl', 'Java', 'Python', 'haskell']"
]
}
],
"prompt_number": 31
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"len('go')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 29,
"text": [
"2"
]
}
],
"prompt_number": 29
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How to sort these without considering the case?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"names = [\"perl\", \"Python\", \"Java\", \"haskell\", \"c\", \"go\"]\n",
"def lower(s): return s.lower()\n",
"sorted(names, key=lower)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 32,
"text": [
"['c', 'go', 'haskell', 'Java', 'perl', 'Python']"
]
}
],
"prompt_number": 32
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# writing the same thing using lambda\n",
"sorted(names, key=lambda s: s.lower())"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 33,
"text": [
"['c', 'go', 'haskell', 'Java', 'perl', 'Python']"
]
}
],
"prompt_number": 33
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Positional and Keyword arguments"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def sub(x, y):\n",
" return x - y"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 34
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print sub(5, 2)\n",
"print sub(5, y=2)\n",
"print sub(x=5, y=2)\n",
"print sub(y=2, x=5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"3\n",
"3\n",
"3\n",
"3\n"
]
}
],
"prompt_number": 35
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Default Arguments"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def incr(x):\n",
" return x+1"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 36
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"incr(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 37,
"text": [
"5"
]
}
],
"prompt_number": 37
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def incr(x, amount=1):\n",
" return x+amount\n",
"\n",
"print incr(5)\n",
"print incr(5, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"6\n",
"9\n"
]
}
],
"prompt_number": 38
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"incr(5, amount=4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 39,
"text": [
"9"
]
}
],
"prompt_number": 39
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Implement a function `unique` that takes a list of values and return a list of unique ones among them. The function should take an optional argument `key`, which is a function used to compare 2 values, just like how sorted works.\n",
"\n",
" >>> unique([\"foo\", \"FooBar\", \"Foo\", \"foo\"])\n",
" [\"foo\", \"FooBar\", \"Foo\"]\n",
" >>> unique([\"foo\", \"FooBar\", \"Foo\", \"foo\"], key=lambda x:x.lower())\n",
" [\"foo\", \"FooBar\"]\n",
" "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def unique(values, key):\n",
" d = {}\n",
" for v in values:\n",
" d[key(v)] = v\n",
" return d.values()\n",
"\n",
"unique([\"foo\", \"FooBar\", \"Foo\", \"foo\"], key=lambda x:x.lower())"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 48,
"text": [
"['FooBar', 'foo']"
]
}
],
"prompt_number": 48
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How to make the key argument optional?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def unique(values, key=None):\n",
" d = {}\n",
" for v in values:\n",
" if key:\n",
" k = key(v)\n",
" else:\n",
" k = v\n",
" d[k] = v\n",
" return d.values()\n",
"unique([\"foo\", \"FooBar\", \"Foo\", \"foo\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 42,
"text": [
"['FooBar', 'foo', 'Foo']"
]
}
],
"prompt_number": 42
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def unique(values, key=None):\n",
" key = key or (lambda x:x)\n",
" d = {}\n",
" for v in values:\n",
" d[key(v)] = v\n",
" return d.values()\n",
"unique([\"foo\", \"FooBar\", \"Foo\", \"foo\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 44,
"text": [
"['FooBar', 'foo', 'Foo']"
]
}
],
"prompt_number": 44
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Default values are computed at the function defination time."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def append(x, values=[]):\n",
" values.append(x)\n",
" return values\n",
"\n",
"print append(3, [1, 2])\n",
"print append(3)\n",
"print append(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3]\n",
"[3]\n",
"[3, 4]\n"
]
}
],
"prompt_number": 50
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def f():\n",
" print \"f\"\n",
" return 1\n",
"\n",
"print \"before defining incr\"\n",
"def incr(x, amount=f()):\n",
" print \"incr\", x, amount\n",
" return x + amount\n",
"print \"after defining incr\"\n",
"\n",
"print incr(3)\n",
"print incr(3, 2)\n",
"print incr(3, 5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"before defining incr\n",
"f\n",
"after defining incr\n",
"incr 3 1\n",
"4\n",
"incr 3 2\n",
"5\n",
"incr 3 5\n",
"8\n"
]
}
],
"prompt_number": 51
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How to handle default values when it should initialized to something like a list?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def append(x, values=None):\n",
" # The default value is now initialized \n",
" # on every call\n",
" if values is None:\n",
" values = []\n",
" values.append(x)\n",
" return values\n",
"\n",
"print append(3, [1, 2])\n",
"print append(3)\n",
"print append(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3]\n",
"[3]\n",
"[4]\n"
]
}
],
"prompt_number": 53
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Assignments in more detail"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = 1\n",
"y = x \n",
"x = 2\n",
"print x, y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"2 1\n"
]
}
],
"prompt_number": 54
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [1, 2]\n",
"y = x\n",
"x.append(3)\n",
"print x\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3]\n",
"[1, 2, 3]\n"
]
}
],
"prompt_number": 55
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [1, 2]\n",
"y = x\n",
"x = [1, 2, 3]\n",
"print x\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3]\n",
"[1, 2]\n"
]
}
],
"prompt_number": 56
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [1, 2]\n",
"y = [x, 5]\n",
"x.append(3)\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[[1, 2, 3], 5]\n"
]
}
],
"prompt_number": 57
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [1, 2]\n",
"y = [x, x]\n",
"x.append(3)\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[[1, 2, 3], [1, 2, 3]]\n"
]
}
],
"prompt_number": 58
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = 0\n",
"y = 0\n",
"def f(x):\n",
" y = x*x\n",
" return y\n",
"\n",
"f(2)\n",
"print x, y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0 0\n"
]
}
],
"prompt_number": 59
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"y = 0\n",
"a = 10\n",
"def f(x):\n",
" y = x+a\n",
" return y\n",
"\n",
"print f(2)\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"12\n",
"0\n"
]
}
],
"prompt_number": 60
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"y = 0\n",
"a = 10\n",
"def f(x):\n",
" print y\n",
" y = x+a\n",
" return y\n",
"\n",
"print f(2)\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "UnboundLocalError",
"evalue": "local variable 'y' referenced before assignment",
"output_type": "pyerr",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mUnboundLocalError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-61-30ff2313577a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 9\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-61-30ff2313577a>\u001b[0m in \u001b[0;36mf\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m10\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mprint\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0my\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0my\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'y' referenced before assignment"
]
}
],
"prompt_number": 61
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"y = 0\n",
"a = 10\n",
"def f(x):\n",
" global y\n",
" print y\n",
" y = x+a\n",
" return y\n",
"\n",
"print f(2)\n",
"print y"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"0\n",
"12\n",
"12\n"
]
}
],
"prompt_number": 62
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def f(x):\n",
" x = x + 1\n",
"\n",
"a = 1\n",
"f(a)\n",
"print a"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n"
]
}
],
"prompt_number": 63
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def f(x):\n",
" x.append(0)\n",
"\n",
"a = [1]\n",
"f(a)\n",
"print a"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 0]\n"
]
}
],
"prompt_number": 64
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Recursion: Function using itself"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def exp(a, n):\n",
" if n == 0:\n",
" return 1\n",
" else:\n",
" return a * exp(a, n-1)\n",
"\n",
"print exp(2, 10)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1024\n"
]
}
],
"prompt_number": 69
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write a function to flatten a nested list.\n"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def flatten_list(values):\n",
" \"\"\"Flattens a nested list.\n",
" \n",
" >>> flatten_list([1, 2, [3, 5], [6, [7]]])\n",
" [1, 2, 3, 4, 5, 6, 7]\n",
" \"\"\"\n",
" result = []\n",
" for v in values:\n",
" if isinstance(v, list):\n",
" result += flatten_list(v)\n",
" else:\n",
" result.append(v)\n",
" return result\n",
"\n",
"flatten_list([1, 2, [3, 5], [6, [7]]])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 74,
"text": [
"[1, 2, 3, 5, 6, 7]"
]
}
],
"prompt_number": 74
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let try to do that without recursion."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def flatten_list(values):\n",
" result = []\n",
" for v in values:\n",
" if isinstance(v, list):\n",
" for v2 in v:\n",
" result.append(v2)\n",
" else:\n",
" result.append(v)\n",
" return result\n",
"flatten_list([1, 2, [3, 5], [6, [7]]])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 75,
"text": [
"[1, 2, 3, 5, 6, [7]]"
]
}
],
"prompt_number": 75
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That not correct. It works for 2 levels.\n",
"\n",
"When the data is recursive, the solution will be mostly recursive."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def json_encode(data):\n",
" if isinstance(data, int):\n",
" return str(data)\n",
" elif isinstance(data, str):\n",
" # will not work if str has quotes in it.\n",
" return '\"' + data + '\"' \n",
" elif isinstance(data, list):\n",
" return \"[\" + \", \".join([json_encode(d) for d in data]) + \"]\"\n",
" \n",
"print json_encode(1)\n",
"print json_encode(\"hello\")\n",
"print json_encode([1, \"hello\"])\n",
"print json_encode([1, \"hello\", [3, [4], 5]])\n",
"print json_encode({\"x\": [1, \"hello\"], \"y\": {\"a\": 2}})\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n",
"\"hello\"\n",
"[1, \"hello\"]\n",
"[1, \"hello\", [3, [4], 5]]\n",
"None\n"
]
}
],
"prompt_number": 83
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Closures - inner functions"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def f(x):\n",
" def adder(y):\n",
" return x + y\n",
" print adder(2)\n",
" \n",
"f(3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"5\n"
]
}
],
"prompt_number": 85
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def make_adder(x):\n",
" def adder(y):\n",
" return x + y\n",
" return adder\n",
"\n",
"add5 = make_adder(5)\n",
"add4 = make_adder(4)\n",
"print add5(3), add4(3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"8 7\n"
]
}
],
"prompt_number": 87
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"More practical use case of this."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"hello\".center(10)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 88,
"text": [
"' hello '"
]
}
],
"prompt_number": 88
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"hello\".center(20)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 89,
"text": [
"' hello '"
]
}
],
"prompt_number": 89
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def make_centeralign(width):\n",
" def f(s):\n",
" return s.center(width)\n",
" return f\n",
"\n",
"center10 = make_centeralign(10)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 91
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# The built-in utility in python standard library\n",
"# allows us to create a new function with some arguments\n",
"# fixed.\n",
"from functools import partial\n",
"import string\n",
"\n",
"center10 = partial(string.center, width=10)\n",
"\n",
"center10('hello')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 96,
"text": [
"' hello '"
]
}
],
"prompt_number": 96
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Functions taking variable number of arguments"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"max(1, 2, 3, 4, 5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 98,
"text": [
"5"
]
}
],
"prompt_number": 98
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_sum(*args):\n",
" print args\n",
" result = 0\n",
" for a in args:\n",
" result += a\n",
" return result\n",
"\n",
"print my_sum(1, 2, 3, 4, 5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"(1, 2, 3, 4, 5)\n",
"15\n"
]
}
],
"prompt_number": 100
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def log(level, *args):\n",
" print \"[%s]\" % level, \" \".join(args)\n",
" \n",
"log(\"INFO\", \"hello\", \"world\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[INFO] hello world\n"
]
}
],
"prompt_number": 101
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def info(*args):\n",
" log(\"INFO\", *args)\n",
"info(\"hello\", \"world\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[INFO] hello world\n"
]
}
],
"prompt_number": 103
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def add(a, b):\n",
" return a + b\n",
"\n",
"print add(1, 2)\n",
"args = [1, 2]\n",
"print add(*args)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"3\n",
"3\n"
]
}
],
"prompt_number": 104
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**keyword arguments**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def render_template(name, **kwargs):\n",
" print \"rendering template %s using %s as arguments\" % (name, kwargs)\n",
" \n",
"render_template(\"index\", user=\"anand\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"rendering template index using {'user': 'anand'} as arguments\n"
]
}
],
"prompt_number": 106
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Decorators"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def square(x):\n",
" print \"square\", 4\n",
" return x\n",
"\n",
"def sum_of_squares(x, y):\n",
" print \"sum_of_squares\", x, y\n",
" return square(x) + square(y)\n",
"\n",
"print sum_of_squares(3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"sum_of_squares 3 4\n",
"square 4\n",
"square 4\n",
"7\n"
]
}
],
"prompt_number": 109
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file trace1.py\n",
"import os\n",
"\n",
"def trace(f):\n",
" def wrapper(*args):\n",
" if os.getenv(\"DEBUG\") == \"true\":\n",
" print f.__name__, args\n",
" return f(*args)\n",
" return wrapper"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting trace1.py\n"
]
}
],
"prompt_number": 125
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file sq.py\n",
"\n",
"from trace1 import trace\n",
"\n",
"\n",
"def square(x):\n",
" return x\n",
"\n",
"square = trace(square)\n",
"\n",
"\n",
"def sum_of_squares(x, y):\n",
" return square(x) + square(y)\n",
"\n",
"sum_of_squares = trace(sum_of_squares)\n",
"\n",
"print sum_of_squares(3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting sq.py\n"
]
}
],
"prompt_number": 128
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python sq.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"7\r\n"
]
}
],
"prompt_number": 129
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!DEBUG=true python sq.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"sum_of_squares (3, 4)\r\n",
"square (3,)\r\n",
"square (4,)\r\n",
"7\r\n"
]
}
],
"prompt_number": 127
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a decorator `logtime`, which prints how much time it look to execute the function.\n",
"\n",
" @logtime\n",
" def square(x):\n",
" return x*x\n",
" \n",
" print square(4)\n",
"\n",
"Will output something like:\n",
"\n",
" square(4) -- took 0.00000001 seconds\n",
" 16"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# hint: use time.time module\n",
"import time\n",
"t0 = time.time()\n",
"for i in range(1000000):\n",
" i*i\n",
"t1 = time.time()\n",
"print \"took\", t1-t0, \"seconds\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"took 0.249258995056 seconds\n"
]
}
],
"prompt_number": 130
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Can a decorator return something other than a function? \n",
"\n",
"Yes, but very unusual."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def notadecor(f):\n",
" return 1\n",
"\n",
"@notadecor\n",
"def square(x): \n",
" return x*x\n",
"\n",
"print square"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n"
]
}
],
"prompt_number": 131
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How does the decorator really work?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def debug(f):\n",
" print \"decorator called with\", f\n",
" def wrapper(x):\n",
" print \"wrapper called with\", x\n",
" print \"calling\", f.__name__, \"with\", x\n",
" result = f(x)\n",
" print f.__name__, \"returned\", result\n",
" print \"returning\", result\n",
" return result\n",
" \n",
" print \"returning wrapper function\", wrapper\n",
" return wrapper\n",
"\n",
"\n",
"print \"before def sqaure\"\n",
"@debug\n",
"def square(x):\n",
" print \"square called with\", x\n",
" return x*x\n",
"print \"after def sqaure\"\n",
"print \n",
"\n",
"print square(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"before def sqaure\n",
"decorator called with <function square at 0x10199b8c0>\n",
"returning wrapper function <function wrapper at 0x10199bb90>\n",
"after def sqaure\n",
"\n",
"wrapper called with 4\n",
"calling square with 4\n",
"square called with 4\n",
"square returned 16\n",
"returning 16\n",
"16\n"
]
}
],
"prompt_number": 141
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets print square now and see what we get."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"square"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 142,
"text": [
"<function __main__.wrapper>"
]
}
],
"prompt_number": 142
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"help(square)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on function wrapper in module __main__:\n",
"\n",
"wrapper(x)\n"
]
}
],
"prompt_number": 143
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def cube(x):\n",
" \"\"\"Computes cube of x\"\"\"\n",
" return x*x*x\n",
"\n",
"help(cube)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Help on function cube in module __main__:\n",
"\n",
"cube(x)\n",
" Computes cube of x\n"
]
}
],
"prompt_number": 144
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print cube.__name__\n",
"print cube.__doc__"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"cube\n",
"Computes cube of x\n"
]
}
],
"prompt_number": 145
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from functools import wraps\n",
"def debug(f):\n",
" @wraps(f)\n",
" def wrapper(x):\n",
" print f.__name__, x\n",
" return f(x)\n",
" print f, wrapper\n",
" return wrapper\n",
"\n",
"@debug\n",
"def square(x):\n",
" return x*x\n",
"\n",
"print square(4)\n",
"print \"---\"\n",
"help(square)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"<function square at 0x10199bed8> <function square at 0x10151d668>\n",
"square 4\n",
"16\n",
"---\n",
"Help on function square in module __main__:\n",
"\n",
"square(x)\n"
]
}
],
"prompt_number": 148
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file trace2.py\n",
"\n",
"indent = 0\n",
"\n",
"def trace(f):\n",
" def wrapper(*args):\n",
" global indent\n",
" sargs = [str(a) for a in args]\n",
" print \"| \" * indent + \"|-- %s(%s)\" % (f.__name__, \", \".join(sargs))\n",
" indent += 1\n",
" result = f(*args)\n",
" indent -= 1\n",
" return result\n",
" return wrapper"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting trace2.py\n"
]
}
],
"prompt_number": 165
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file sq2.py\n",
"\n",
"from trace2 import trace\n",
"\n",
"@trace\n",
"def multiply(a, b):\n",
" return a*b\n",
"\n",
"@trace\n",
"def square(x):\n",
" return multiply(x, x)\n",
"\n",
"@trace\n",
"def sum_of_squares(x, y):\n",
" return square(x) + square(y)\n",
"print sum_of_squares(3, 4)\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting sq2.py\n"
]
}
],
"prompt_number": 171
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python sq2.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"|-- sum_of_squares(3, 4)\r\n",
"| |-- square(3)\r\n",
"| | |-- multiply(3, 3)\r\n",
"| |-- square(4)\r\n",
"| | |-- multiply(4, 4)\r\n",
"25\r\n"
]
}
],
"prompt_number": 172
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file fib1.py\n",
"from trace2 import trace\n",
"\n",
"@trace\n",
"def fib(n):\n",
" if n == 0 or n == 1:\n",
" return 1\n",
" else:\n",
" return fib(n-1) + fib(n-2)\n",
"\n",
"print fib(5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Writing fib1.py\n"
]
}
],
"prompt_number": 173
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python fib1.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"|-- fib(5)\r\n",
"| |-- fib(4)\r\n",
"| | |-- fib(3)\r\n",
"| | | |-- fib(2)\r\n",
"| | | | |-- fib(1)\r\n",
"| | | | |-- fib(0)\r\n",
"| | | |-- fib(1)\r\n",
"| | |-- fib(2)\r\n",
"| | | |-- fib(1)\r\n",
"| | | |-- fib(0)\r\n",
"| |-- fib(3)\r\n",
"| | |-- fib(2)\r\n",
"| | | |-- fib(1)\r\n",
"| | | |-- fib(0)\r\n",
"| | |-- fib(1)\r\n",
"8\r\n"
]
}
],
"prompt_number": 174
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file memoize.py\n",
"import functools\n",
"\n",
"def memoize(f):\n",
" cache = {}\n",
" @functools.wraps(f)\n",
" def wrapper(*args):\n",
" if args not in cache:\n",
" cache[args] = f(*args)\n",
" return cache[args]\n",
" return wrapper"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting memoize.py\n"
]
}
],
"prompt_number": 187
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file fib2.py\n",
"from trace2 import trace\n",
"from memoize import memoize\n",
"\n",
"@memoize\n",
"@trace\n",
"def fib(n):\n",
" if n == 0 or n == 1:\n",
" return 1\n",
" else:\n",
" return fib(n-1) + fib(n-2)\n",
"\n",
"print fib(5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting fib2.py\n"
]
}
],
"prompt_number": 185
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python fib2.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"|-- fib(5)\r\n",
"| |-- fib(4)\r\n",
"| | |-- fib(3)\r\n",
"| | | |-- fib(2)\r\n",
"| | | | |-- fib(1)\r\n",
"| | | | |-- fib(0)\r\n",
"8\r\n"
]
}
],
"prompt_number": 186
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a decorator `ignore_exceptions` that catches and ignores the exceptions raised by the wrapped function. It should also print the exception before ignoring.\n",
"\n",
" @ignore_exceptions\n",
" def wget(url):\n",
" return urllib2.urlopen(url).read()\n",
" \n",
" wget(\"http://google.com/no-such-page\")\n",
"\n",
"should print something like:\n",
"\n",
" Failed to download http://google.com/no-such-page : Not Found"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a decorator `with_retry` that retries for 5 times with a delay of 1 second if the wrapped function raises exception. After 5 attempts, it print the error message and ignores the exception.\n",
"\n",
"\n",
" @with_retry\n",
" def wget(url):\n",
" return urllib2.urlopen(url).read()\n",
" \n",
" wget(\"http://google.com/no-such-page\")\n",
"\n",
"Should print something like:\n",
"\n",
" (1) Error Not Found. retrying...\n",
" (2) Error Not Found. retrying...\n",
" (3) Error Not Found. retrying...\n",
" (4) Error Not Found. retrying...\n",
" (5) Error Not Found. retrying...\n",
" Giving up."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you look at the above example, it would be really nice to specify number of retries when decorating the function. \n",
"\n",
" @with_retry(retries=5, delay=0.5)\n",
" def wget(url):\n",
" ...\n",
" \n",
"We may want to use similar pattern for memoize for timeouts.\n",
"\n",
" @memoize(timeout=60)\n",
" def get_recent_posts(site):\n",
" ..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Example: memoize with timeouts**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import functools\n",
"import time\n",
"\n",
"def memoize_with_timeout(timeout):\n",
" def decorator(f):\n",
" cache = {}\n",
" @functools.wraps(f)\n",
" def wrapper(*args):\n",
" entry = cache.get(args)\n",
" t = time.time()\n",
" # we are storing (value, time)\n",
" # so entry[0] will be the value \n",
" # and entry[1] will be the time\n",
" if not entry or entry[1]+timeout < t:\n",
" if not entry:\n",
" print \"no entry found in cache, recomputing\"\n",
" else:\n",
" print \"entry is stale (%.2f seconds old), recomputing\" % (t-entry[1])\n",
" cache[args] = f(*args), t \n",
" else:\n",
" print \"found an entry(%0.2f seconds old), reusing\" % (t-entry[1])\n",
" return cache[args][0]\n",
" return wrapper\n",
" return decorator \n",
" \n",
"\"\"\"\n",
"@memoize_with_timeout(timeout=2) \n",
"def longrunning_func():\n",
" time.sleep(1)\n",
" return time.time()\n",
"\n",
"def longrunning_func():\n",
" time.sleep(1)\n",
" return time.time()\n",
"\n",
"decorator = memoize_with_timeout(timeout=2)\n",
"longrunning_func = decorator(longrunning_func) \n",
"\"\"\"\n",
"\n",
"@memoize_with_timeout(.4)\n",
"def f():\n",
" return time.time()\n",
"\n",
"for i in range(10):\n",
" value = f()\n",
" print i, value\n",
" time.sleep(.1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"no entry found in cache, recomputing\n",
"0 1384420653.14\n",
"found an entry(0.10 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"1 1384420653.14\n",
"found an entry(0.20 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"2 1384420653.14\n",
"found an entry(0.30 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"3 1384420653.14\n",
"entry is stale (0.40 seconds old), recomputing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"4 1384420653.55\n",
"found an entry(0.10 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"5 1384420653.55\n",
"found an entry(0.20 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"6 1384420653.55\n",
"found an entry(0.30 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"7 1384420653.55\n",
"entry is stale (0.41 seconds old), recomputing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"8 1384420653.95\n",
"found an entry(0.10 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"9 1384420653.95\n"
]
}
],
"prompt_number": 201
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are some tricks to reduce the levels of nesting and make it easier to read."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import functools\n",
"import time\n",
"\n",
"def memoize_with_timeout(f=None, timeout=0):\n",
" if f is None:\n",
" # The following can also be used:\n",
" # return functools.partial(memoize_with_timeout, timeout=timeout)\n",
" def decor(f):\n",
" return memoize_with_timeout(f, timeout=timeout)\n",
" return decor\n",
" \n",
" cache = {}\n",
" @functools.wraps(f)\n",
" def wrapper(*args):\n",
" entry = cache.get(args)\n",
" t = time.time()\n",
" # we are storing (value, time)\n",
" # so entry[0] will be the value \n",
" # and entry[1] will be the time\n",
" if not entry or entry[1]+timeout < t:\n",
" if not entry:\n",
" print \"no entry found in cache, recomputing\"\n",
" else:\n",
" print \"entry is stale (%.2f seconds old), recomputing\" % (t-entry[1])\n",
" cache[args] = f(*args), t \n",
" else:\n",
" print \"found an entry(%0.2f seconds old), reusing\" % (t-entry[1])\n",
" return cache[args][0]\n",
" return wrapper\n",
" \n",
"@memoize_with_timeout(timeout=.4)\n",
"def f():\n",
" return time.time()\n",
"\n",
"for i in range(10):\n",
" value = f()\n",
" print i, value\n",
" time.sleep(.1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"no entry found in cache, recomputing\n",
"0 1384422586.23\n",
"found an entry(0.10 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"1 1384422586.23\n",
"found an entry(0.20 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"2 1384422586.23\n",
"found an entry(0.30 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"3 1384422586.23\n",
"entry is stale (0.40 seconds old), recomputing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"4 1384422586.64\n",
"found an entry(0.10 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"5 1384422586.64\n",
"found an entry(0.20 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"6 1384422586.64\n",
"found an entry(0.30 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"7 1384422586.64\n",
"entry is stale (0.41 seconds old), recomputing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"8 1384422587.04\n",
"found an entry(0.10 seconds old), reusing"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"9 1384422587.04\n"
]
}
],
"prompt_number": 205
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem:** Write a decorator function `with_retries` which takes `retries`, `delay` and `ignore_error` as arguments. If `ignore_error` is `True`, it ignores the error after retries. If it is False, it re-raises the last exception.\n",
"\n",
" @with_retries(retries=5, delay=0.5, ignore_error=True)\n",
" def wget(url):\n",
" return urllib2.urlopen(url).read()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Example: web framework**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets try to build a simple web framework using decorators. It'll have all moving parts of a web framework except network."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file bicycle.py\n",
"\"\"\"The bicycle web framework\n",
"\"\"\"\n",
"\n",
"# mapping from paths to functions\n",
"mapping = []\n",
"\n",
"def route(path):\n",
" def decorator(f):\n",
" mapping.append((path, f))\n",
" return f\n",
" return decorator\n",
" \n",
" \n",
"def request(path):\n",
" for p, func in mapping:\n",
" if p == path:\n",
" return func()\n",
" \n",
" print \"404 Not Found\"\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting bicycle.py\n"
]
}
],
"prompt_number": 220
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file webapp.py\n",
"\n",
"from bicycle import route, request\n",
"\n",
"@route(\"/\")\n",
"def index():\n",
" print \"Welcome\"\n",
"\n",
"@route(\"/hello\")\n",
"def hello():\n",
" print \"hello\"\n",
"\n",
"if __name__ == \"__main__\":\n",
" request(\"/\")\n",
" request(\"/hello\")\n",
" request(\"/no-such-page\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting webapp.py\n"
]
}
],
"prompt_number": 221
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python webapp.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Welcome\r\n",
"hello\r\n",
"404 Not Found\r\n"
]
}
],
"prompt_number": 222
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a decorator `before_request` that register a function to be called before each request.\n",
"\n",
" @before_request\n",
" def header():\n",
" print \"======\"\n",
" print \"HEADER\"\n",
" print \"======\"\n",
" print\n",
" \n",
" @route(\"/\")\n",
" def index():\n",
" print \"Welcome\"\n",
" \n",
" request(\"/\")\n",
" \n",
"should print:\n",
" \n",
" ======\n",
" HEADER\n",
" ======\n",
" \n",
" Welcome"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ideas to improve the framework.\n",
"\n",
"* Pass query string as keyword arguments to request func.\n",
"\n",
" request(\"/login\", username=\"joe\", password=\"secret\")\n",
" \n",
" bicycle.input() when called from your app should return {\"username\": \"joe\", \"password\": \"secret\"}\n",
" \n",
" request(\"/hello\", name=\"joe\", repeat=\"10\")\n",
" \n",
"\n"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment