{ "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.1" }, "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[![Py4Life](https://raw.githubusercontent.com/Py4Life/TAU2015/gh-pages/img/Py4Life-logo-small.png)](http://py4life.github.io/TAU2015/)\n", "\n", "## Lecture 5 - 15.4.2015\n", "### Last update: 15.4.2015\n", "### Tel-Aviv University / 0411-3122 / Spring 2015" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Previously\n", "\n", "- Modules\n", "- Files I/O\n", "- The CSV format\n", "- File parsing\n", "- Regular expression\n", "\n", "# Today\n", "\n", "- Bugs\n", "- Debugging\n", "- Tests and assertions\n", "- Exceptions\n", "\n", "# Homework\n", "\n", "Please submit a project abstract by _May 1st_ via Moodle." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Testing & Debugging\n", "\n", "> Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. _ \u2014 B. W. Kernighan and P. J. Plauger, [The Elements of Programming Style](http://www.amazon.com/gp/product/0070342075?ie=UTF8&tag=catv-20&linkCode=as2&camp=1789&creative=390957&creativeASIN=0070342075).\n", "\n", "> Code that cannot be tested is flawed.\n", "\n", "> Why do we never have time to do it right, but always have time to do it over?\n", "\n", "> Fast, good, cheap: pick any two. - _[Project management triangle](http://en.wikipedia.org/wiki/Project_management_triangle)_\n", "\n", "![bugs](http://assets.nydailynews.com/polopoly_fs/1.1064084!/img/httpImage/image.jpg_gen/derivatives/landscape_635/bugs01-web.jpg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Bug categories\n", "\n", "## Errors\n", "\n", "`SyntaxError`: Illegal Python code. This error will appear when the program is preparing to run." ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = . 5" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "SyntaxError", "evalue": "invalid syntax (, line 1)", "output_type": "pyerr", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m x = . 5\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often the error is precisely indicated, as above, but sometimes you have to search for the error on the previous line.\n", "\n", "`IndentationError`: a line in the code has bad indentation\u05e5" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = 7\n", " b = 5" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "IndentationError", "evalue": "unexpected indent (, line 2)", "output_type": "pyerr", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m2\u001b[0m\n\u001b[1;33m b = 5\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mIndentationError\u001b[0m\u001b[1;31m:\u001b[0m unexpected indent\n" ] } ], "prompt_number": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can be tricky at times, because sometimes the indentation seems OK but Python still complains -- this is usually because the indentation is in spaces when it needs to be in tabs, or vice versa.\n", "\n", "The next sample of errors are _runtime_ errors - they only appear when the program is running. \n", "Therefore, they can be elusive: these bugs don't always appear because they depend on variable values and program flow.\n", "\n", "`NameError`: A name (variable, function, module) is not defined." ] }, { "cell_type": "code", "collapsed": false, "input": [ "b = a + 2" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'a' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0ma\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mNameError\u001b[0m: name 'a' is not defined" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Look at the _Tracebck_ to see where in the program the error occurs. The most common reasons for a `NameError` are\n", "\n", "- a misspelled name,\n", "- a variable that is not initialized,\n", "- a function that you have forgotten to define,\n", "- a module that is not imported.\n", "\n", "Working in the IPython Notebook can introduce such errors when you forget to run a cell and use the variables from that cell in another cell.\n", "\n", "`TypeError`: An object of wrong type is used in an operation." ] }, { "cell_type": "code", "collapsed": false, "input": [ "n = 1\n", "x = '2'\n", "product = (1.0/(n+1))*(x/(1.0+x))**(n+1)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "unsupported operand type(s) for +: 'float' and 'str'", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'2'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mproduct\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[1;36m1.0\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mn\u001b[0m\u001b[1;33m+\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m*\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1.0\u001b[0m\u001b[1;33m+\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m**\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mn\u001b[0m\u001b[1;33m+\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'float' and 'str'" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print out objects and their types (here: `print(x, type(x), n, type(n))`), and you will most likely get a surprise. The reason for a `TypeError` is often far away from the line where the `TypeError` occurs.\n", "\n", "`ValueError`: An object has an illegal value." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import math\n", "z = -1\n", "math.sqrt(z)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "math domain error", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mmath\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mmath\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msqrt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mz\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mValueError\u001b[0m: math domain error" ] } ], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print out the value of objects that can be involved in the error (here: `print(z)`).\n", "\n", "`IndexError`: An index in a list, tuple, or a string is too large." ] }, { "cell_type": "code", "collapsed": false, "input": [ "values = [1,27,33,46,52]\n", "n = 0\n", "for i in range(len(values)):\n", " n += values[i+1]" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "IndexError", "evalue": "list index out of range", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mIndexError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mn\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalues\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0mn\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mvalues\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m+\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mIndexError\u001b[0m: list index out of range" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print out the length of the list, and the index if it involves a variable (here: `print(len(values), i)`).\n", "\n", "`KeyError`: this is `IndexError`'s cousin; it is raised when looking up non-existant keys in a `dict`. \n", "Remember that you can use `dict.get(key, default_value)` to prevent this error." ] }, { "cell_type": "code", "collapsed": false, "input": [ "d = {}\n", "d['a']" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "KeyError", "evalue": "'a'", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0md\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0md\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'a'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mKeyError\u001b[0m: 'a'" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "print(d.get('a'))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "None\n" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 1 - Errors\n", "\n", "Let's solve the following bugs. Each notebook cell has a single program with at least one bug that may either cause an error or make the program incorrect (producing wrong results).\n", "\n", "**Fix the code.**" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = '7'\n", "y = 8\n", "z = x + y\n", "print(z)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "Can't convert 'int' object to str implicitly", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'7'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0my\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m8\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mz\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mz\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mTypeError\u001b[0m: Can't convert 'int' object to str implicitly" ] } ], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "x = 1\n", "y = 0\n", "while x < 4:\n", " y += x\n", "print(y)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "KeyboardInterrupt", "evalue": "", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0my\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;32mwhile\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m \u001b[0my\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mx\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 5\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mKeyboardInterrupt\u001b[0m: " ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "switch = 'on'\n", "if switch = 'off':\n", " print('go home')" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "SyntaxError", "evalue": "invalid syntax (, line 2)", "output_type": "pyerr", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m2\u001b[0m\n\u001b[1;33m if switch = 'off':\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m invalid syntax\n" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "range()" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "range expected 1 arguments, got 0", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: range expected 1 arguments, got 0" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "range(2.5)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'float' object cannot be interpreted as an integer", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2.5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: 'float' object cannot be interpreted as an integer" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "range(2,3,0)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "range() arg 3 must not be zero", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mValueError\u001b[0m: range() arg 3 must not be zero" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "counter = 0\n", "while counter < 5:\n", " print('hello')\n", " counter += 1\n", "while counter < 5:\n", " print('bye')\n", " counter += 1" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hello\n", "hello\n", "hello\n", "hello\n", "hello\n" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Logical bugs\n", "\n", "Some bugs don't cause errors. These are risky because we can easily miss them. For example, this function for the [sum of a geometric series](http://en.wikipedia.org/wiki/Geometric_series#Formula):\n", "\n", "$$\n", "\\sum_{k>=1}{a r^k} = \\frac{a}{1-r}\n", "$$" ] }, { "cell_type": "code", "collapsed": true, "input": [ "def geosum(a, r):\n", " return a/(1 - r)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This works well for some values, causes errors for other values, and gives incorrect results for yet other values:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(\"Correct:\")\n", "print(geosum(1,0), 1)\n", "print(geosum(1,0.5), 2)\n", "print(geosum(0,0.5), 0)\n", "print(geosum(0,2), 0)\n", "\n", "print(\"Incorrect:\")\n", "print(geosum(1,2), \"\\u221e\")\n", "print(geosum(-1,2), \"-\\u221e\")\n", "print(geosum(2,-1), \"NaN\")\n", "\n", "print(\"Error:\")\n", "print(geosum(1,1))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Correct:\n", "1.0 1\n", "2.0 2\n", "0.0 0\n", "-0.0 0\n", "Incorrect:\n", "-1.0 \u221e\n", "1.0 -\u221e\n", "1.0 NaN\n", "Error:\n" ] }, { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Error:\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mgeosum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;32m\u001b[0m in \u001b[0;36mgeosum\u001b[1;34m(a, r)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mgeosum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0ma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0ma\u001b[0m\u001b[1;33m/\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mZeroDivisionError\u001b[0m: division by zero" ] } ], "prompt_number": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ "For this kind of bugs we have to write **tests**. \n", "\n", "The simplest way to do this is using [`assert` statements](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement). \n", "The `assert` command will check a statement and if it is `False` it will raise an `AssertionError`. You can also attach a message explaining why the assertion the failed:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "assert geosum(1,0) == 1, \"Bad value\"\n", "assert geosum(1,0.5) == 2, \"Bad value\"\n", "assert geosum(0,0.5) == 0, \"Bad value\"\n", "assert geosum(0,2) == 0, \"Bad value\"\n", "\n", "assert geosum(1,2) == None, \"Bad value\"\n", "assert geosum(-1,2) == None, \"Bad value\"\n", "assert geosum(2,-1) == None, \"Bad value\"\n", "assert geosum(1,1) == None, \"Bad value\"" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "Bad value", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAssertionError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;32massert\u001b[0m \u001b[0mgeosum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Bad value\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[1;32massert\u001b[0m \u001b[0mgeosum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Bad value\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 7\u001b[0m \u001b[1;32massert\u001b[0m \u001b[0mgeosum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Bad value\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;32massert\u001b[0m \u001b[0mgeosum\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Bad value\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mAssertionError\u001b[0m: Bad value" ] } ], "prompt_number": 33 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's fix the function:" ] }, { "cell_type": "code", "collapsed": true, "input": [ "def geosum(a, r):\n", " if a == 0:\n", " return 0.0 # always return same type \n", " elif abs(r) >= 1:\n", " return None # formula only defined for |r|<1\n", " return a/(1 - r)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "assert geosum(1,0) == 1, \"Bad value\"\n", "assert geosum(1,0.5) == 2, \"Bad value\"\n", "assert geosum(0,0.5) == 0, \"Bad value\"\n", "assert geosum(0,2) == 0, \"Bad value\"\n", "\n", "assert geosum(1,2) == None, \"Bad value\"\n", "assert geosum(-1,2) == None, \"Bad value\"\n", "assert geosum(2,-1) == None, \"Bad value\"\n", "assert geosum(1,1) == None, \"Bad value\"" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are more sophisticated ways to write tests. \n", "The [unittest](https://docs.python.org/3/library/unittest.html) module is a good starting point and [nose](https://nose.readthedocs.org/en/latest/) is _nicer testing for Python_." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise 2 - test\n", "\n", "Below is a function that calculates the length of the largest side of a right triangle given the lengths of the other two sides using the [Pythagorean theorem](http://en.wikipedia.org/wiki/Pythagorean_theorem):\n", "\n", "$$\n", "a^2 + b^2 = c^2\n", "$$\n", "\n", "![Pythagorean theorem](http://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Pythagorean.svg/265px-Pythagorean.svg.png)" ] }, { "cell_type": "code", "collapsed": true, "input": [ "def pythagoras(a,b):\n", " return math.sqrt(a**2 + b**2)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Write a series of assertions to test the function." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# Your code goes here" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Live debugging - find genes in a sequence\n", "\n", "We will write a program that looks for genes (or open reading frames) in a DNA sequence.\n", "\n", "How do we go about it? Let's make a plan.\n", "\n", "### The plan\n", "\n", "1. What _exactly_ do we want?\n", "\n", "2. What is the input and output?\n", "\n", "3. Example\n", "\n", "4. Algorithm - one function to check if a sequence is a gene; one function to look for gene candidates in a sequence\n", "\n", "5. Implementation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 1. What _exactly_ do we want?\n", "\n", "We want to find all genes in a DNA sequence, including overlapping genes, but only on the sequence, not on its complement.\n", "\n", "A valid gene: (i) contains only the bases AGCT, (ii) starts with a start codon (ATG), (iii) ends with a stop codon (TAG, TGA, TAA), (iv) its length is a multiple of three, (v) and doesn't contain a stop codon in a position that is a multiple of three.\n", "\n", "#### 2. What is the input and output?\n", "\n", "Input: string.\n", "\n", "Output: list of strings.\n", "\n", "#### 3. Example\n", "\n", "Our example is GCCGTTTGTACTCCATTCCA**ATGAGGTCGCTTC|ATGTCAGCGAGTTTTAA**CGTGGTTCTTCGCTG**A|TGTGCTGTATATGA**.\n", "\n", "This is a good example because it is (i) not too short to be trivial, (ii) not too long to be unreadable, (iii) contains genes in at least two different open reading frames and (iv) overlapping genes.\n", "\n", "- Input: `GCCGTTTGTACTCCATTCCAATGAGGTCGCTTCATGTCAGCGAGTTTTAACGTGGTTCTTCGCTGATGTGCTGTATATGA`\n", "- Output: `['ATGAGGTCGCTTCATGTCAGCGAGTTTTAA', 'ATGTCAGCGAGTTTTAACGTGGTTCTTCGCTGA', 'ATGTGCTGTATATGA']`\n", "\n", "#### 4. Algorithm\n", "\n", "Here is a skeleton of our program with a **test case** (_i.e._ assertion), which, of course, fails for now. \n", "This is called [_test driven development_](http://en.wikipedia.org/wiki/Test-driven_development) (it may sound like this is only for \"serious\" programmers. The contrary is true - it's very beneficial for less expirienced programmers)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def is_gene(sequence):\n", " # check if sequence Trueis a gene\n", " return False\n", "\n", "def find_genes(sequence):\n", " # find all genes in sequence\n", " return []\n", "\n", "seq = 'GCCGTTTGTACTCCATTCCAATGAGGTCGCTTCATGTCAGCGAGTTTTAACGTGGTTCTTCGCTGATGTGCTGTATATGA'\n", "genes = find_genes(seq)\n", "assert len(genes) == 3, \"Found %d genes, expected 3\" % len(genes)\n", "print(\"Success\")" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "AssertionError", "evalue": "Found 0 genes, expected 3", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mAssertionError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[0mseq\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'GCCGTTTGTACTCCATTCCAATGAGGTCGCTTCATGTCAGCGAGTTTTAACGTGGTTCTTCGCTGATGTGCTGTATATGA'\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m \u001b[0mgenes\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mfind_genes\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mseq\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[1;32massert\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mgenes\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m\"Found %d genes, expected 3\"\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mgenes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 12\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Success\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mAssertionError\u001b[0m: Found 0 genes, expected 3" ] } ], "prompt_number": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 5. Implementation\n", "\n", "Here is the code that implements the program.\n", "\n", "Now we must test and debug!" ] }, { "cell_type": "code", "collapsed": false, "input": [ "bases = \"ACGT\"\n", "start = \"ATG\"\n", "stops = [\"TAg\",\"TGG\",\"TAA\"]\n", "\n", "def is_gene(sequence):\n", " if len(seqeunce) < 5: # check minimum length \n", " return False\n", " if len(sequence) % 3 ! 0: # check length divides by 3\n", " return False\n", " if sequence[1:3] != start: # check start codon\n", " return False\n", " # check stop codon\n", " if sequence[-3:] not in stops: \n", " return False\n", " # check only legal characters\n", " for c in sequence: \n", " if c not in bases:\n", " return False\n", " # check no stop codons in the middle \n", " for i in range(0, len(sequence) - 3, 3): \n", " if sequence[i:i+3] in stops:\n", " return False\n", " return \"True\"\n", "\n", "def find_genes(sequence):\n", " start_idx = []\n", " for i in range(len(sequence)):\n", " if sequence[i,i+3] == start:\n", " start_idx.append(i) \n", " stop_idx = []\n", " for i in range(len(sequence)):\n", " if sequence[i,i+3] == stops:\n", " stop_idx.append(i) \n", " for i == start_idx:\n", " for j == stop_idx:\n", " if j <= i and j-i % 3 == 0:\n", " gene = sequence[i,j+3]\n", " if is_gene(genes):\n", " genes.append(genes)\n", " return gene\n", "\n", "seq = 'GCCGTTTGTACTCCATTCCAATGAGGTCGCTTCATGTCAGCGAGTTTTAACGTGGTTCTTCGCTGATGTGCTGTATATGA'\n", "genes = find_genes(seq)\n", "assert len(genes) == 3, \"Found %d genes, expected 3\" % len(genes)\n", "print(\"Success\")" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "IndentationError", "evalue": "expected an indented block (, line 7)", "output_type": "pyerr", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m7\u001b[0m\n\u001b[1;33m return False\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mIndentationError\u001b[0m\u001b[1;31m:\u001b[0m expected an indented block\n" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Let's debug!\n", "\n", "We will use several strategies:\n", "\n", "- adding diagnostic `print` statements to see variable values\n", "- narrowing down problems by reducing and fixing variable values\n", "- tests using assertions\n", "- comment out code" ] }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": null }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Here is a working version of the code.\n", "How do we know it's _working_? Because **the assertion succeeds**." ] }, { "cell_type": "code", "collapsed": false, "input": [ "bases = \"ACGT\"\n", "start = \"ATG\"\n", "stops = [\"TAG\",\"TGA\",\"TAA\"]\n", "\n", "def is_gene(sequence):\n", " if len(sequence) < 6: # check minimum length \n", " return False\n", " if len(sequence) % 3 != 0: # check length divides by 3\n", " return False\n", " if sequence[:3] != start: # check start codon\n", " return False\n", " # check stop codon\n", " if sequence[-3:] not in stops: \n", " return False\n", " # check only legal characters\n", " for c in sequence: \n", " if c not in bases:\n", " return False\n", " # check no stop codons in the middle \n", " for i in range(0, len(sequence) - 6, 3): \n", " if sequence[i:i+3] in stops:\n", " return False\n", " return True\n", "\n", "def find_genes(sequence):\n", " start = \"ATG\"\n", " stops = [\"TAG\",\"TGA\",\"TAA\"]\n", " start_idx = []\n", " for i in range(len(sequence) - 2):\n", " if sequence[i:i+3] == start:\n", " start_idx.append(i)\n", " stop_idx = []\n", " for i in range(len(sequence) - 2):\n", " if sequence[i:i+3] in stops:\n", " stop_idx.append(i)\n", " genes = []\n", " for i in start_idx:\n", " for j in stop_idx:\n", " if j > i and (j-i)%3==0:\n", " gene = sequence[i:j+3]\n", " if is_gene(gene):\n", " genes.append(gene)\n", " return genes\n", "\n", "seq = 'GCCGTTTGTACTCCATTCCAATGAGGTCGCTTCATGTCAGCGAGTTTTAACGTGGTTCTTCGCTGATGTGCTGTATATGA'\n", "genes = find_genes(seq)\n", "assert len(genes) == 3, \"Found %d genes, expected 3\" % len(genes)\n", "print(\"Success\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Success\n" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "### Summary\n", "\n", "This plan outline can be changed according to the problem but the basic idea is: \n", "\n", "- understand the problem\n", "- find examples to use as tests\n", "- write the test\n", "- design an algorithm\n", "- implement the algorithm\n", "- test and debug until test succeeds\n", "\n", "This example follows the outline of an [example](http://hplgit.github.io/teamods/debugging/._debug004.html) by Hans Petter Langtangen. \n", "The problem is burrowed from a [Python for engineers exam](http://www.cs.tau.ac.il/courses/pyProg/1415a/exams/PyProg1415a_moedA_solution.pdf)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Try and except\n", "\n", "Errors (also called _exceptions_) can be caught and handled, if you know how to handle them.\n", "\n", "For example, trying to open a file that does not exist gives a `FileNotFoundError`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "filename = \"myfile.txt\"\n", "with open(filename) as f:\n", " print(f.read())" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "FileNotFoundError", "evalue": "[Errno 2] No such file or directory: 'myfile.txt'", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mfilename\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m\"myfile.txt\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'myfile.txt'" ] } ], "prompt_number": 52 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can catch the error using a `try-except` and either recover from the error (if you can) or handle it differently. For example, we can alert the user on the problem without the \"ugly\" error:" ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Exception: `FileNotFoundError` trying to open non-existing file" ] }, { "cell_type": "code", "collapsed": false, "input": [ "filename = \"myfile.txt\"\n", "with open(filename) as f:\n", " print(f.read())" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "FileNotFoundError", "evalue": "[Errno 2] No such file or directory: 'myfile.txt'", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mfilename\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m\"myfile.txt\"\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfilename\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mf\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'myfile.txt'" ] } ], "prompt_number": 4 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Catch with `try`-`except`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "filename = \"myfile.txt\"\n", "try:\n", " with open(filename) as f:\n", " print(f.read())\n", "except FileNotFoundError:\n", " print(\"File\",filename,\"not found, please try a different filename\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "File myfile.txt not found, please try a different filename\n" ] } ], "prompt_number": 5 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Exception: `ValueError` on parsing a number" ] }, { "cell_type": "code", "collapsed": false, "input": [ "number = input(\"Give me a number please: \")\n", "number = int(number)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Give me a number please: python\n" ] }, { "ename": "ValueError", "evalue": "invalid literal for int() with base 10: 'python'", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mnumber\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0minput\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Give me a number please: \"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mnumber\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnumber\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mValueError\u001b[0m: invalid literal for int() with base 10: 'python'" ] } ], "prompt_number": 14 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Catch with `try`-`except`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "number = input(\"Give me a number please: \")\n", "try:\n", " number = int(number)\n", "except ValueError:\n", " print(\"I asked for a number and you gave me:\", number)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Give me a number please: python\n", "I asked for a number and you gave me: python\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise - *Sabotage* and protein mass\n", "\n", "Here's a nice little program that calculates the mass of a protein given the amino acid sequence of the protein." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from urllib import request\n", "request.urlretrieve(\"https://raw.githubusercontent.com/Py4Life/TAU2015/master/aa_weights.txt\", \"aa_weights.txt\")" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 6, "text": [ "('aa_weights.txt', )" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "with open(\"aa_weights.txt\") as f:\n", " weights = {}\n", " for line in f:\n", " aa,w = line.strip().split()\n", " w = float(w)\n", " weights[aa] = w\n", "print(weights)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "{'D': 115.02694, 'E': 129.04259, 'R': 156.10111, 'S': 87.03203, 'M': 131.04049, 'W': 186.07931, 'P': 97.05276, 'C': 103.00919, 'V': 99.06841, 'I': 113.08406, 'G': 57.02146, 'A': 71.03711, 'L': 113.08406, 'N': 114.04293, 'T': 101.04768, 'K': 128.09496, 'Q': 128.05858, 'H': 137.05891, 'F': 147.06841, 'Y': 163.06333}\n" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": true, "input": [ "def protein_mass(sequence):\n", " mass = 0\n", " for aa in sequence:\n", " if aa not in weights:\n", " raise ValueError(\"Input sequence contains an illegal aa: %s\" % aa)\n", " mass += weights[aa]\n", " return mass" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "seq = 'SKADYEK'\n", "assert round(protein_mass(seq), 3) == 821.392\n", "print(\"Success\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Success\n" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Open the notebook on your computer and sabotage the program by hiding exactly 5 bugs in the code.\n", "\n", "Now, change seats with a partner and find the bugs that your partner hid in the code.\n", "\n", "The problem protein mass problem appears in [Rosalind](http://rosalind.info/problems/prtm/). \n", "The *Sabotage* exercise is burrowed from a post in the [Teach Computing](https://teachcomputing.wordpress.com/2013/11/23/sabotage-teach-debugging-by-stealth/) blog by [Alan O'Donohoe](https://twitter.com/teknoteacher)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# References\n", "\n", "- [Debugging in Python](http://hplgit.github.io/teamods/debugging/debug.html) by Hans Petter Langtangen. Some of the material here is borrowed or influenced from this wonderful resource. Check it out for more debugging tips, examples and methods.\n", "\n", "- [Sabotage: Teach Debugging By Stealth](https://teachcomputing.wordpress.com/2013/11/23/sabotage-teach-debugging-by-stealth/) by Alan O'Donohoe" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fin\n", "This notebook is part of the _Python Programming for Life Sciences Graduate Students_ course given in Tel-Aviv University, Spring 2015.\n", "\n", "The notebook was written using [Python](http://pytho.org/) 3.4.1 and [IPython](http://ipython.org/) 3.1 (download from [PyZo](http://www.pyzo.org/downloads.html), update with `conda update ipython ipython-notebook`).\n", "\n", "The code is available at https://github.com/Py4Life/TAU2015/blob/master/lecture5.ipynb.\n", "\n", "The notebook can be viewed online at http://nbviewer.ipython.org/github/Py4Life/TAU2015/blob/master/lecture5.ipynb.\n", "\n", "This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.\n", "\n", "![Python logo](https://www.python.org/static/community_logos/python-logo.png)" ] } ], "metadata": {} } ] }