Skip to content

Instantly share code, notes, and snippets.

@anandology anandology/day1.ipynb
Last active Aug 29, 2015

Embed
What would you like to do?
Advanced Python Training at LinkedIn -- Feb 26 - Mar 1, 2014
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Advanced Python Training - Day 1\n",
"Linked In<br/>\n",
"Feb 26 - Mar 1, 2014<br/>\n",
"<a href=\"http://anandology.com\">Anand Chitipothu</a>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Warmup"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# problem 2\n",
"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": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Functions in Detail"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Default Arguments"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def inc(x, amount=1):\n",
" return x + amount\n",
"\n",
"print inc(4)\n",
"print inc(4, 2)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"5\n",
"6\n"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a function `centeralign` that takes a string and width as argument and aligns to center. If the second argument is not provided it should take 40 as the default width.\n",
"\n",
" >>> centeralign(\"hello\", 9)\n",
" ' hello '\n",
" >>> centeralign('abcdefghijklmnopqrstuvwxyz')\n",
" ' abcdefghijklmnopqrstuvwxyz '\n",
" >>> print centeralign(\"a\", 9); print centeralign(\"abc\", 9); print centeralign(\"abcde\", 9)\n",
" a\n",
" abc\n",
" abcde"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Pitfalls of default arguments**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def add_first_column(data, result=[]):\n",
" \"\"\"Adds all values in the first column\n",
" of data to result.\n",
" \"\"\"\n",
" for row in data:\n",
" value = row[0]\n",
" result.append(value)\n",
" return result\n",
"\n",
"data = [[1, 2], [2, 4], [3, 9]]\n",
"print add_first_column(data, ['colum 0'])\n",
"print add_first_column(data)\n",
"print add_first_column(data)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['colum 0', 1, 2, 3]\n",
"[1, 2, 3]\n",
"[1, 2, 3, 1, 2, 3]\n"
]
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is not a good idea to have mutable objects as values of default arguments."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def add_first_column2(data, result=None):\n",
" \"\"\"Adds all values in the first column\n",
" of data to result.\n",
" \"\"\"\n",
" if result is None:\n",
" result = []\n",
" for row in data:\n",
" value = row[0]\n",
" result.append(value)\n",
" return result\n",
"\n",
"data = [[1, 2], [2, 4], [3, 9]]\n",
"print add_first_column2(data, ['colum 0'])\n",
"print add_first_column2(data)\n",
"print add_first_column2(data)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['colum 0', 1, 2, 3]\n",
"[1, 2, 3]\n",
"[1, 2, 3]\n"
]
}
],
"prompt_number": 11
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**varargs and kwargs**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"max(1, 2, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 12,
"text": [
"4"
]
}
],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"max(1, 2, 3, 4, 78, 98)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 13,
"text": [
"98"
]
}
],
"prompt_number": 13
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def f(*args):\n",
" print args\n",
" \n",
"f()\n",
"f(1)\n",
"f(1, 2)\n",
"f(1, 2, 3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"()\n",
"(1,)\n",
"(1, 2)\n",
"(1, 2, 3)\n"
]
}
],
"prompt_number": 14
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Implement a function `add` that takes variable number of arguments and returns their sum.\n",
"\n",
" >>> add(1, 2, 3)\n",
" 6\n",
" >>> add(1, 2, 3, 4)\n",
" 10"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def xprint(label, *args):\n",
" for a in args:\n",
" print label, a"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 19
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"xprint(\"[INFO]\", 1, 2, 3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[INFO] 1\n",
"[INFO] 2\n",
"[INFO] 3\n"
]
}
],
"prompt_number": 20
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a function `strjoin` that takes a delimiter as first argument followed by variable number of strings and joins them with the delimiter.\n",
"\n",
" >> strjoin(\"-\", \"a\", \"b\", \"c\")\n",
" 'a-b-c'"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"dict(a=1, b=2)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 21,
"text": [
"{'a': 1, 'b': 2}"
]
}
],
"prompt_number": 21
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def my_dict(**kwargs):\n",
" return kwargs\n",
" \n",
"my_dict(a=1, b=2)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 23,
"text": [
"{'a': 1, 'b': 2}"
]
}
],
"prompt_number": 23
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def render_tag(tagname, **attrs):\n",
" pairs = ['%s=\"%s\"' % (k, v) for k, v in attrs.items()]\n",
" return \"<%s %s>\" % (tagname, \" \".join(pairs))\n",
"\n",
"print render_tag(\"a\", \n",
" href=\"http://linkedin.com\", \n",
" id=\"xx\",\n",
" rel=\"nofollow\")\n",
"\n",
"print render_tag(\"input\", \n",
" type=\"text\",\n",
" name=\"x\",\n",
" value=\"10\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"<a href=\"http://linkedin.com\" id=\"xx\" rel=\"nofollow\">\n",
"<input type=\"text\" name=\"x\" value=\"10\">\n"
]
}
],
"prompt_number": 31
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There is new way of doing string formatting, I guess since Python 2.7."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"Hello {}\".format(\"Python\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 32,
"text": [
"'Hello Python'"
]
}
],
"prompt_number": 32
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"{0} {1}\".format(\"Hello\", \"Python\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 33,
"text": [
"'Hello Python'"
]
}
],
"prompt_number": 33
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"{msg} {name}\".format(msg=\"Hello\", name=\"Python\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 34,
"text": [
"'Hello Python'"
]
}
],
"prompt_number": 34
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\"%(msg)s %(name)s\" % {\"msg\": \"Hello\", \"name\": \"Python\"}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 36,
"text": [
"'Hello Python'"
]
}
],
"prompt_number": 36
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we have all args as a list or dict, how do we call a function with those as args?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"args = [1, 2, 3, 4]"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 37
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def add(*args):\n",
" return sum(args)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 39
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"add(1, 2, 3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 40,
"text": [
"10"
]
}
],
"prompt_number": 40
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def incr(x, amount=1):\n",
" return x+amount"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 41
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"args1 = [10]\n",
"args2 = [10, 5]\n",
"kwargs3 = {\"x\": 10, \"amount\": 5}\n",
"args4 = [10]\n",
"kwargs4 = {\"amount\": 5}"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 53
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# How can we call incr with args1 and args2 as arguments?\n",
"# We need to unpack the args and send to the function.\n",
"print incr(*args1)\n",
"print incr(*args2)\n",
"print incr(**kwargs3)\n",
"print incr(*args4, **kwargs4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"11\n",
"15\n",
"15\n",
"15\n"
]
}
],
"prompt_number": 54
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a function `call_func` that takes a function and variable number of arguments and calls the given function and arguments.\n",
"\n",
" >>> def diff(a, b): return a-b\n",
" ...\n",
" >>> call_func(diff, 5, 3)\n",
" 2\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem:** Can you improve the above `call_func` to support keyword arguments as well?\n",
"\n",
" >>> def diff(a, b): return a-b\n",
" ...\n",
" >>> call_func(diff, b=3, a=5)\n",
" 2\n",
" >>> call_func(dict, x=1, y=2)\n",
" {'x': 1, 'y': 2}"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def call_func(func, *args, **kwargs):\n",
" return func(*args, **kwargs)\n",
"\n",
"def diff(a, b): return a-b\n",
"\n",
"print call_func(diff, 5, 3)\n",
"print call_func(diff, a=5, b=3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"2\n",
"2\n"
]
}
],
"prompt_number": 56
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print call_func(render_tag, \"input\", type=\"text\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"<input type=\"text\">\n"
]
}
],
"prompt_number": 57
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Recursion"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Example: Flattening a list**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [1, 2, 3, [4, 5, [6, 7], 8], 9]"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 58
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def flatten_list0(values):\n",
" result = []\n",
" for v in values:\n",
" if isinstance(v, list):\n",
" result.extend(v)\n",
" else:\n",
" result.append(v)\n",
" return result\n",
"\n",
"print flatten_list0(x)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3, 4, 5, [6, 7], 8, 9]\n"
]
}
],
"prompt_number": 59
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def flatten_list1(values):\n",
" result = []\n",
" for v in values:\n",
" if isinstance(v, list):\n",
" result.extend(flatten_list1(v))\n",
" else:\n",
" result.append(v)\n",
" return result\n",
"\n",
"print flatten_list1(x)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
]
}
],
"prompt_number": 60
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def flatten_list2(values, result=None):\n",
" if result is None:\n",
" result = []\n",
" for v in values:\n",
" if isinstance(v, list):\n",
" flatten_list2(v, result)\n",
" else:\n",
" result.append(v)\n",
" return result\n",
"\n",
"print flatten_list2(x)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
]
}
],
"prompt_number": 61
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a function `nested_reverse` to reverse elemenets of a nested list recursively.\n",
"\n",
" >>> nested_reverse([[1, 2], [3, [4, 5] ], 6])\n",
" [6, [[5, 4], 3], [2, 1]]"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def nested_reverse(values):\n",
" if not isinstance(values, list):\n",
" return values\n",
" return [nested_reverse(v) for v in values][::-1]\n",
"\n",
"print nested_reverse([[1, 2], [3, [4, 5] ], 6])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[6, [[5, 4], 3], [2, 1]]\n"
]
}
],
"prompt_number": 63
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Example: json_encode**"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How to convert a python datastructure to JSON?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def json_encode(value):\n",
" if isinstance(value, int):\n",
" return str(value)\n",
" elif isinstance(value, str):\n",
" # simplified implementation\n",
" # will not work if value has quotes in it.\n",
" return '\"' + value + '\"'\n",
" elif isinstance(value, list):\n",
" elems = [json_encode(v) for v in value]\n",
" return \"[\" + \", \".join(elems) + \"]\"\n",
" elif isinstance(value, dict):\n",
" elems = [json_encode(k) + \": \" + json_encode(v) \n",
" for k, v in value.items()] \n",
" return \"{\" + \", \".join(elems) + \"}\"\n",
" \n",
"print json_encode(1)\n",
"print json_encode(\"hello\")\n",
"print json_encode([\"a\", \"b\", 5, \"c\"])\n",
"print json_encode([\"a\", \"b\", [\"c\", [\"d\", \"e\"], \"f\"]])\n",
"print json_encode({\"a\": 1, \"b\": 2, \"c\": 3})\n",
"print json_encode({\"a\": 1, \"b\": [2, {\"c\": 3}]})"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"1\n",
"\"hello\"\n",
"[\"a\", \"b\", 5, \"c\"]\n",
"[\"a\", \"b\", [\"c\", [\"d\", \"e\"], \"f\"]]\n",
"{\"a\": 1, \"c\": 3, \"b\": 2}\n",
"{\"a\": 1, \"b\": [2, {\"c\": 3}]}\n"
]
}
],
"prompt_number": 81
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Improve the above `json_encode` function by adding support for encoding dictionaries."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Higher Order Functions"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sorted([\"Python\", \"Ruby\", \"Java\", \"C\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 83,
"text": [
"['C', 'Java', 'Python', 'Ruby']"
]
}
],
"prompt_number": 83
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sorted([\"Python\", \"Ruby\", \"Java\", \"C\"], key=len)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 84,
"text": [
"['C', 'Ruby', 'Java', 'Python']"
]
}
],
"prompt_number": 84
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"max([\"Python\", \"Ruby\", \"Java\", \"C\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 85,
"text": [
"'Ruby'"
]
}
],
"prompt_number": 85
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"max([\"Python\", \"Ruby\", \"Java\", \"C\"], key=len)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 86,
"text": [
"'Python'"
]
}
],
"prompt_number": 86
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a function `maximum` that finds max of given values. If optional argument key is provided it should compare `key(x)` and `key(y)` instead of comparing x and y."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def maximum0(values):\n",
" result = values[0]\n",
" for v in values:\n",
" if v > result:\n",
" result = v\n",
" return result\n",
"\n",
"print maximum0([1,2, 4, 3])\n",
"print maximum0([\"Python\", \"Ruby\", \"Java\", \"C\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"4\n",
"Ruby\n"
]
}
],
"prompt_number": 89
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def maximum1(values, key=None):\n",
" result = values[0]\n",
" for v in values:\n",
" if key:\n",
" if key(v) > key(result):\n",
" result = v\n",
" else:\n",
" if v > result:\n",
" result = v\n",
" return result\n",
"\n",
"print maximum1([\"Python\", \"Ruby\", \"Java\", \"C\"], key=len)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Python\n"
]
}
],
"prompt_number": 90
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def identity(x):\n",
" return x\n",
"\n",
"def maximum2(values, key=None):\n",
" if key is None:\n",
" key = identity\n",
" \n",
" result = values[0]\n",
" for v in values:\n",
" if key(v) > key(result):\n",
" result = v\n",
" return result\n",
"\n",
"print maximum2([\"Python\", \"Ruby\", \"Java\", \"C\"], key=len)\n",
"print maximum2([\"Python\", \"Ruby\", \"Java\", \"C\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Python\n",
"Ruby\n"
]
}
],
"prompt_number": 95
},
{
"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": 92
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f = square"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 93
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"f(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 94,
"text": [
"16"
]
}
],
"prompt_number": 94
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Lambda Functions**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"square = lambda x: x*x"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 96
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"square(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 97,
"text": [
"16"
]
}
],
"prompt_number": 97
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"names = [\"Python\", \"Ruby\", \"java\", \"C\", \"c++\"]\n",
"print sorted(names)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['C', 'Python', 'Ruby', 'c++', 'java']\n"
]
}
],
"prompt_number": 98
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def lower(name): return name.lower()\n",
"print sorted(names, key=lower)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['C', 'c++', 'java', 'Python', 'Ruby']\n"
]
}
],
"prompt_number": 99
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print sorted(names, key=lambda x: x.lower())"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"['C', 'c++', 'java', 'Python', 'Ruby']\n"
]
}
],
"prompt_number": 101
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Nested Functions / Closures**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def make_adder(x):\n",
" def adder(y):\n",
" return x+y\n",
" print adder(5)\n",
" \n",
"make_adder(3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"8\n"
]
}
],
"prompt_number": 102
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def make_adder(x):\n",
" def adder(y):\n",
" return x+y\n",
" return adder\n",
" \n",
"add3 = make_adder(3)\n",
"add5 = make_adder(5)\n",
"\n",
"print add3(10)\n",
"print add5(10)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"13\n",
"15\n"
]
}
],
"prompt_number": 107
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"z = 100\n",
"def make_adder1(x):\n",
" def adder(y):\n",
" return x+y+z\n",
" print x+z\n",
" print adder(5)\n",
" \n",
"make_adder1(3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"103\n",
"108\n"
]
}
],
"prompt_number": 109
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"z = 100\n",
"def make_adder2(x):\n",
" def adder(y):\n",
" return x+y+z\n",
" return adder\n",
" \n",
"add3 = make_adder2(3)\n",
"print add3(5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"108\n"
]
}
],
"prompt_number": 110
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"dir(add3)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 111,
"text": [
"['__call__',\n",
" '__class__',\n",
" '__closure__',\n",
" '__code__',\n",
" '__defaults__',\n",
" '__delattr__',\n",
" '__dict__',\n",
" '__doc__',\n",
" '__format__',\n",
" '__get__',\n",
" '__getattribute__',\n",
" '__globals__',\n",
" '__hash__',\n",
" '__init__',\n",
" '__module__',\n",
" '__name__',\n",
" '__new__',\n",
" '__reduce__',\n",
" '__reduce_ex__',\n",
" '__repr__',\n",
" '__setattr__',\n",
" '__sizeof__',\n",
" '__str__',\n",
" '__subclasshook__',\n",
" 'func_closure',\n",
" 'func_code',\n",
" 'func_defaults',\n",
" 'func_dict',\n",
" 'func_doc',\n",
" 'func_globals',\n",
" 'func_name']"
]
}
],
"prompt_number": 111
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"add3.__closure__"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 112,
"text": [
"(<cell at 0x102db41a0: int object at 0x100311f48>,)"
]
}
],
"prompt_number": 112
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"add3.func_closure[0].cell_contents"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 118,
"text": [
"3"
]
}
],
"prompt_number": 118
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem:** Write a function `make_centeralign` that takes width as argument and returns a function that centeraligns given string for that width.\n",
"\n",
" >>> center9 = make_centeralign(9)\n",
" >>> center9('hello')\n",
" ' hello '"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def sort_by_column(data, colindex):\n",
" return sorted(data, key=lambda row: row[colindex])\n",
"\n",
"data = [[\"a\", 5], [\"b\", 3], [\"d\", 2], [\"c\", 7]]\n",
"print sort_by_column(data, 0)\n",
"print sort_by_column(data, 1)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[['a', 5], ['b', 3], ['c', 7], ['d', 2]]\n",
"[['d', 2], ['b', 3], ['a', 5], ['c', 7]]\n"
]
}
],
"prompt_number": 122
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Can a nested function change value of a variable defined in the scope above?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def f(x):\n",
" def incr():\n",
" x = x + 1\n",
" print x\n",
" incr()\n",
" print x\n",
"\n",
"f(5) "
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "UnboundLocalError",
"evalue": "local variable 'x' 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-123-d2b7fdf4740d>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mx\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[0mf\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-123-d2b7fdf4740d>\u001b[0m in \u001b[0;36mf\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0mincr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mx\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<ipython-input-123-d2b7fdf4740d>\u001b[0m in \u001b[0;36mincr\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\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[1;32m 2\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mincr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mincr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'x' referenced before assignment"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"5\n"
]
}
],
"prompt_number": 123
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = 10\n",
"def f():\n",
" x = 5\n",
" \n",
"f()\n",
"print x"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"10\n"
]
}
],
"prompt_number": 124
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [10]\n",
"def f():\n",
" x = [5]\n",
" \n",
"f()\n",
"print x"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[10]\n"
]
}
],
"prompt_number": 125
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"x = [10]\n",
"def f():\n",
" x[0] = 5\n",
" \n",
"f()\n",
"print x"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"[5]\n"
]
}
],
"prompt_number": 126
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Decorators"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"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": [
"8\n"
]
}
],
"prompt_number": 137
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def trace(f):\n",
" def g(x):\n",
" print f.__name__, \"called with\", x\n",
" return f(x)\n",
" return g\n",
"\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",
"fib = trace(fib)\n",
"print fib(5)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"fib called with 5\n",
"fib called with 4\n",
"fib called with 3\n",
"fib called with 2\n",
"fib called with 1\n",
"fib called with 0\n",
"fib called with 1\n",
"fib called with 2\n",
"fib called with 1\n",
"fib called with 0\n",
"fib called with 3\n",
"fib called with 2\n",
"fib called with 1\n",
"fib called with 0\n",
"fib called with 1\n",
"8\n"
]
}
],
"prompt_number": 142
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def trace(f):\n",
" def g(x):\n",
" print f.__name__, \"called with\", x\n",
" return f(x)\n",
" return g\n",
"\n",
"# this is decorator syntax\n",
"# which is short hand to say:\n",
"# fib = trace(fib)\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": [
"fib called with 5\n",
"fib called with 4\n",
"fib called with 3\n",
"fib called with 2\n",
"fib called with 1\n",
"fib called with 0\n",
"fib called with 1\n",
"fib called with 2\n",
"fib called with 1\n",
"fib called with 0\n",
"fib called with 3\n",
"fib called with 2\n",
"fib called with 1\n",
"fib called with 0\n",
"fib called with 1\n",
"8\n"
]
}
],
"prompt_number": 144
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"level = 0\n",
"\n",
"def trace(f):\n",
" def g(x):\n",
" global level\n",
" print \"| \" * level + \"|-- \" + f.__name__, x\n",
" level += 1\n",
" value = f(x)\n",
" level -= 1 \n",
" return value\n",
" return g\n",
"\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": [
"|-- fib 5\n",
"| |-- fib 4\n",
"| | |-- fib 3\n",
"| | | |-- fib 2\n",
"| | | | |-- fib 1\n",
"| | | | |-- fib 0\n",
"| | | |-- fib 1\n",
"| | |-- fib 2\n",
"| | | |-- fib 1\n",
"| | | |-- fib 0\n",
"| |-- fib 3\n",
"| | |-- fib 2\n",
"| | | |-- fib 1\n",
"| | | |-- fib 0\n",
"| | |-- fib 1\n",
"8\n"
]
}
],
"prompt_number": 148
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets write trace as a module."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file trace1.py\n",
"import functools\n",
"\n",
"level = 0\n",
"def trace(f):\n",
" @functools.wraps(f)\n",
" def g(*args):\n",
" global level\n",
" print \"| \" * level + \"|-- \" + f.__name__, args\n",
" level += 1\n",
" value = f(*args)\n",
" level -= 1 \n",
" return value\n",
" return g"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting trace1.py\n"
]
}
],
"prompt_number": 156
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file squares.py\n",
"from trace1 import trace\n",
"\n",
"@trace\n",
"def square(x):\n",
" \"\"\"Computes square of a number.\"\"\"\n",
" return x*x\n",
"\n",
"@trace\n",
"def sum_of_squares(x, y):\n",
" return square(x)+square(y)\n",
"\n",
"if __name__ == \"__main__\":\n",
" print sum_of_squares(3, 4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting squares.py\n"
]
}
],
"prompt_number": 159
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python squares.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",
"25\r\n"
]
}
],
"prompt_number": 160
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a decorator function `logtime` that takes a function as argument and returns a new function that behaves exactly like the given function, except that it prints the time it took to execute.\n",
"\n",
" @logtime\n",
" def timepass(n):\n",
" sum = 0\n",
" for i in range(n):\n",
" for j in range(n):\n",
" sum += i*j\n",
" return sum\n",
" \n",
" # should print time taken before printing the result\n",
" print timepass(10000)\n"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def decorator(f):\n",
" print \"defined function\", f.__name__\n",
" def g(*args):\n",
" print \"before calling function\", f.__name__\n",
" result = f(*args)\n",
" print \"after calling function\", f.__name__\n",
" return result\n",
" return g\n",
"\n",
"@decorator\n",
"def square(x):\n",
" return x*x"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"defined function square\n"
]
}
],
"prompt_number": 161
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"square(4)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"before calling function square\n",
"after calling function square\n"
]
},
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 162,
"text": [
"16"
]
}
],
"prompt_number": 162
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file logtime.py\n",
"import time\n",
"\n",
"def logtime(f):\n",
" def g(*args):\n",
" t0 = time.time()\n",
" value = f(*args)\n",
" t1 = time.time()\n",
" print \"took\", t1-t0, \"seconds\"\n",
" return value\n",
" return g\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting logtime.py\n"
]
}
],
"prompt_number": 168
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file timepass.py\n",
"from logtime import logtime\n",
"\n",
"@logtime\n",
"def timepass(n):\n",
" sum = 0\n",
" for i in range(n):\n",
" for j in range(n):\n",
" sum += i*j\n",
" return sum\n",
"\n",
"print timepass(1000)\n",
"print timepass(2000)\n",
"print timepass(4000)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting timepass.py\n"
]
}
],
"prompt_number": 174
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python timepass.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"took 0.122349023819 seconds\r\n",
"249500250000\r\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"took 0.399986028671 seconds\r\n",
"3996001000000\r\n"
]
},
{
"output_type": "stream",
"stream": "stdout",
"text": [
"took 1.50092315674 seconds\r\n",
"63968004000000\r\n"
]
}
],
"prompt_number": 175
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Example: memoize**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file memoize.py\n",
"\n",
"import functools\n",
"\n",
"def memoize(f):\n",
" cache = {}\n",
" @functools.wraps(f)\n",
" def g(*args):\n",
" if args not in cache:\n",
" cache[args] = f(*args)\n",
" return cache[args]\n",
" return g\n",
"\n",
"if __name__ == \"__main__\":\n",
" @memoize\n",
" def square(n):\n",
" print \"square\", n\n",
" return n*n\n",
" \n",
" for x in [4, 4, 5, 4, 5]:\n",
" print square(x)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting memoize.py\n"
]
}
],
"prompt_number": 179
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!python memoize.py"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"square 4\r\n",
"16\r\n",
"16\r\n",
"square 5\r\n",
"25\r\n",
"16\r\n",
"25\r\n"
]
}
],
"prompt_number": 180
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file fib2.py\n",
"from trace1 import trace\n",
"from memoize import memoize\n",
"\n",
"@memoize\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",
"if __name__ == \"__main__\":\n",
" import sys\n",
" print fib(int(sys.argv[1]))"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting fib2.py\n"
]
}
],
"prompt_number": 201
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"!time python fib2.py 300"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"359579325206583560961765665172189099052367214309267232255589801\r\n",
"\r\n",
"real\t0m0.026s\r\n",
"user\t0m0.015s\r\n",
"sys\t0m0.009s\r\n"
]
}
],
"prompt_number": 200
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Webapp - part 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Problem** Write a Python script to generate HTML files to display photos in the given directory as an album. The script should generate an index.html file showing thumbnails of all the images and one html file for each image with next and prev links.\n",
"\n",
"\n",
"\n",
"Sample photos and sample html file are available at <http://anandology.com/tmp/album.zip>.\n",
"\n",
"See <http://nbviewer.ipython.org/gist/anandology/8663909/day3.ipynb> for more details about the problem.\n",
"\n",
"Hints:\n",
"\n",
"* To display an image in smaller size, add with to the img tag. `<img src=\"photo1.jpg\" width=\"100\">`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Templates**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from jinja2 import Template\n",
"\n",
"t = Template(\"Hello {{name}}\")\n",
"print t.render(name=\"Jinja\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Hello Jinja\n"
]
}
],
"prompt_number": 202
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file hello1.html\n",
"Hello {{name}}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Writing hello1.html\n"
]
}
],
"prompt_number": 203
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def render_template(filename, **kwargs):\n",
" t = Template(open(filename).read())\n",
" return t.render(**kwargs)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 204
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print render_template(\"hello1.html\", name=\"Python\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Hello Python\n"
]
}
],
"prompt_number": 205
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%file hello2.html\n",
"{% for name in names %}\n",
"Hello {{ name }}.\n",
"{% endfor %}"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Overwriting hello2.html\n"
]
}
],
"prompt_number": 209
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print render_template(\"hello2.html\", \n",
" names=[\"a\", \"b\", \"c\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"\n",
"Hello a.\n",
"\n",
"Hello b.\n",
"\n",
"Hello c.\n",
"\n"
]
}
],
"prompt_number": 210
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
You can’t perform that action at this time.