{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Notebook-4: Dealing with Errors & Debugging" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Lesson Topics: \n", "\n", "- Introduction to errors \n", " - Syntax Errors\n", " - Exceptions \n", "- How to read errors\n", "- Learn to find help\n", "\n", "Welcome to the third Code Camp notebook! This lesson is all about learning to deal with the (unavoidable) errors that you wil encounter when programming in Ptyhon. Most programmers spend _most_ of their day dealing with errors of one sort or another: sometimes they are easy to solve (e.g. you mis-typed a variable name), other times they are very, very hard (e.g. you are writing a cloud computing platform and have to deal with competition for resources). Either way, learning how to find, diagnose, and resolve errors, as well as how to minimize their consequences, is thus a crucial skill for programmers. \n", "\n", "*Acknowledgement: This notebook is heavily based on the [official Python Documentation](https://docs.python.org/2/tutorial/errors.html) about Errors and Exception. Check it out for further examples.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "# Introduction to errors\n", "\n", "In the preceding notebooks we've already pointed out a few simple errors and made some suggestions about how to read them, but as you have seen when there's something wrong Python stops whatever it's doing and prints out an error message.\n", "\n", "Run the next code cell and examine the error message:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "print \"Ouch!\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The error gives you a helpful clue as to what is going wrong: it's something to do with the Syntax.\n", "```python\n", " Input In [1]\n", " print \"Ouch!\"\n", " ^ \n", "SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?\n", "```\n", "In this case it even tells you what the most _likely_ resolution is: we need to use `()` with the `print` function (i.e. `print(\"Ouch!\")`). Not all errors are as easy to diagnose, but by carefully reviewing the output it is often possible to get a pretty good _sense_ of where things are going wrong. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And here's another, our familiar \"division by zero\" example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "45 / 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This error also gives you a helpful clue: You can't divide by zero!\n", "```python\n", "ZeroDivisionError Traceback (most recent call last)\n", " in \n", "----> 1 45 / 0\n", "\n", "ZeroDivisionError: division by zero\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see, depending on what just broke we see different error messages fromy the Python interpreter. Although it's not the most crucial distinction, there are roughly two main kinds of errors: **Syntax Errors** and **Exceptions**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Syntax Errors\n", "\n", "A Syntax Error is likely to the be the most frequent error you encounter when you're getting started. Syntax errors occur when the Python interpreter has trouble *[parsing](https://en.wikipedia.org/wiki/Parsing)* your code. In other words, it can read what you've typed but it doesn't quite make sense.\n", "\n", "It's a bit like when someone who doesn't speak your language fluently makes a mistake that to you seems funny, but to them is quite natural because they're extrapolating from what they know in a different language. Many English-speakers who are 'embarassed' by their level of Spanish are also apparently happy to inform Spanish-speakers that they are pregnant ('embarazada')! Or perhaps you think that the opposite of 'regardless' is 'irregardless'? These are natural mistakes, but they are 'errors' nonetheless. It's just that human beings – being smart – can figure out what you meant, while computers – being almost irredeemably stupid – cannot." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A simple typo\n", "In the first example for instance, the error consists in a `print` command missing its parentheses:\n", "\n", "```python\n", " Input In [1]\n", " print \"Ouch!\"\n", " ^ \n", "SyntaxError: Missing parentheses in call to 'print'. Did you mean print(...)?\n", "```\n", "\n", "Let's read the error message together, from top-to-bottom: \n", "- First, the interpreter prints out the line number where it thinks the error can be found. In our simple case that's not a big deal since we only have one line of code anyway, but if you had thousands of lines of code spread across dozens of separate files this could be a life-saver!\n", "- In addition, Python also prints the _actual_ line where it threw up its hands and said \"I can't read this!\" \n", "- It has even added a little 'caret' ( ‸ ) to try to point out where on that line it _thinks_ the error is. We wouldn't recommend that you study _only_ that bit of the code but it's not a bad place to start.. \n", "- Lastly, Python prints out very clearly that the error is something to do with the syntax and in this case _even_ suggests a solution.\n", "\n", "Let's try to see if you can fix some bits of broken code by reading the errors and spotting the place where I've made some mistakes." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A Challenge for You!\n", "\n", "Run the next two code cells and use the error messages to see if you can fix the following problems:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "projection=\"Cassini-Soldner\" \n", "print(\"The \" projection + \" projection preserves distances along the central meridian.\")" ] }, { "cell_type": "markdown", "metadata": { "solution2": "hidden", "solution2_first": true }, "source": [ "In this case do you think the suggested solution is the best? Or maybe we just need to add a `+`? _Beware_: the suggested solution to an error (by the computer) is not always the one you want!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "projection=\"Cassini-Soldner\" \n", "print(\"The \" + projection + \" projection preserves distances along the central meridian.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "other_projection \"Mollweide\"\n", "print(\"In the \" + other_projection + \" projection, meridians are ellipses.\")" ] }, { "cell_type": "markdown", "metadata": { "solution2": "hidden", "solution2_first": true }, "source": [ "In this error we don't even get a suggestion of what to do to fix it! To identify the solution, first check which line the error occures on. Then, think about how assignment works (from a previous notebook). " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "other_projection=\"Mollweide\"\n", "print(\"In the \" + other_projection + \" projection, meridians are ellipses.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exceptions\n", "\n", "Even if your code is syntatically exemplary (i.e. it's all perfectly written before you hit 'run'), errors might still occur for a wide variety of reasons: your computer is freaking out, you're not online, you haven't defined a variable yet... Obviously, these aren't syntax errors because your code would ordinarly work fine, it's just that something is missing and we think this is... _exceptional_. \n", "\n", "To help you find out which of the problems you've just hit, Python has the concept of exceptions and a huge taxonomy of specific errors ([here's a list](https://docs.python.org/2/library/exceptions.html)). That way, when something exceptional happens we know whether to restart the computer, check the Internet connection, or look for the place where the variable was supposedly defined.\n", "\n", "Let's start by considering these two *exception* examples (run each and examine the error message returned):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"london has an approx. popoulation of \"+ popn + \" million people \")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What do you think is going on here? What type of error have we received? (we'll examine the specific issue below). \n", "\n", "And this one:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\"london has an approx. popoulation of\" + 8.5 + \"million people \"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What 'type' of exception is this?\n", "\n", "We've seen `TypeError` before: remember that programmers don't like to write 'string' when they could write 'str', and that 'float' means 'floating point number'." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now let's reconsider the `ZeroDivisionError` Exception:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "4 / 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First of all we can see that every exception displays a specific message in the last line which gives you useful information about what just went wrong. That's because* exceptions* are different from plain *syntax errors* because they come in different types which are recognized by Python and printed accordingly. In our three examples above the *Exceptions* were: `NameError`, `TypeError`and `ZeroDivisionError`. These are the *exception types*.\n", "\n", "As with the *syntax errors*, the remaining part of the error message gives us useful pointers to how to go about fixing the code:\n", "\n", "- Once again Python starts with the location. This time though, it doesn't immediately point to a specific line but rather it explicits the *stack traceback*[1](https://en.wikipedia.org/wiki/Stack_trace),[2](https://en.wikipedia.org/wiki/Call_stack#STACK-FRAME) level (i.e. **very roughly speaking** the list of operations active in your code) where some mischief happened. \n", "\n", "- Luckly, there's a line reference in the following line (see the purple arrow (--->) pointing at line 1)\n", "\n", "```python\n", "Input In [5], in ()\n", "----> 1 print(\"london has an approx. popoulation of \"+ popn + \" million people \")\n", "\n", "NameError: name 'popn' is not defined\n", "\n", "```\n", "\n", "In the `NameError` example, the problem is that we have not yet created a variable named `popn` (we would need something like `popn = \"8.5\"` on the line prior to printing; the 8.5 in `\"\"` to avoid the `TypeError`). " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "popn = \"8.5\"\n", "print(\"london has an approx. popoulation of \"+ popn + \" million people \")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Do you see how these are different from *Syntax Errors* conceptually and that they require you to do something different? Indeed, *Exceptions* are clearly specified in the language for two main reasons:\n", "\n", "- It allows you to restrict the range of possibilities regarding what went wrong, allowing faster and easier debugging. \n", "- Because exceptions are \"named\" errors, they're easier for the programmer to \"catch\" when the code is running. \n", "\n", "In other words, you can't know in advance whether your application will always have Internet access, so rather than just having your program 'blow up' or say \"Can't run, sorry!\", wouldn't it be better if it printed a helpful message to the user saying \"Hey, I don't seem to be online. Can you check the network connection?\" So in Python, one part of the application can 'throw' an exception (\"Hey, I'm not online\") when it tries to download a file and then it's up to the application to _catch_ that problem and print a warning to the user.\n", "\n", "If you see any of the following commands `TRY/EXCEPT/FINALLY` then that means a programmer is trying to limit the damage that could be caused by an exception." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### A Challenge for You!\n", "\n", "Run the next three code cells and use the error messages to see if you can fix the following problems:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "london_population = 8600000\n", "print(\"London's population is \" + london_population)" ] }, { "cell_type": "raw", "metadata": { "solution2": "hidden", "solution2_first": true }, "source": [ "HINT: Think about the _type_ of data that `london_population` holds _and_ how to convert a number into a string with the appropriate function" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "london_population = 8600000\n", "print(\"London's population is \" + str(london_population))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "london_population / paris_population" ] }, { "cell_type": "markdown", "metadata": { "solution2": "hidden", "solution2_first": true }, "source": [ "HINT: Define a new variable with the amount of people living in the French capital (2.2 million) " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "paris_population = 2200000\n", "london_population / paris_population" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"The ratio of london_population to paris_population is \" + london_population / paris_population)" ] }, { "cell_type": "markdown", "metadata": { "solution2": "hidden", "solution2_first": true }, "source": [ "HINT: Think about the data type the result of the calculation needs to be" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "print(\"The ratio of london_population to paris_population is \" + str(london_population / paris_population))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# How to read errors\n", "---\n", "\n", "Here's a \"rule of thumb\" list of actions to take when Python throws an error at you:\n", "\n", "- *Don't Panic!*\n", "- Take a deep breath and *READ CAREFULLY* the error message.\n", "- Ask yourself: is it a *Syntax Error* or an *Exception*?\n", "- In both cases: where's the faulty line?\n", "- For *Syntax Errors*: where's the little caret character ( ‸ ) pointing at?\n", "- For *Exceptions*: what kind of exception is that? Read the [Official Docs](https://docs.python.org/2/library/exceptions.html) and try to make sense of it\n", "- *No, really. Don't Panic!*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Learn to find help\n", "---\n", "\n", "We can't say this enough: [Google is your friend!](http://lmgtfy.com/?q=%22Learning+what+questions+to+ask+is+a+skill+in+itself%22+-Somebody+smart). And we really mean it. \n", "\n", "![stackOverflow](img/stack-overflow.jpg)\n", "\n", "If learning how to interpret error messages is the first step to fixing broken code, the _second_ one (before you think about asking for help) is doing your 'homework'. And since you're not the first students to learn to program, there's a pretty good chance that someone has had your problem -- or one very similar to it -- before. \n", "\n", "The largest website/community/forum online that programmers from all over the world use on a daily basis is **StackOverflow**. The name itself is a nerdy inside joke referring to a *bad* situation in programming:\n", "\n", ">When a program attempts to use more space than is available on the call stack... the stack is said to overflow, typically resulting in a program crash. (source: [Wikipedia](https://en.wikipedia.org/wiki/Stack_overflow) )\n", "\n", "As the name implies, it's often the first resource that you want to consult if your program is not behaving as expected. For a quick overview of it's features refer directly to [StackOverflow's intro section](http://stackoverflow.com/tour).\n", "\n", "Often, you don't end up even needing to ask a question at all because the answer is already somewhere on Stack Overflow. But if, after carefully checking the site, you still can't find an answer to your problem then it's time to start thinking about asking your own question. \n", "\n", "In order to maximise your chances of success (and to avoid flooding the board with unclear and repetitive questions) read thoroughly the [How do I ask a good question?](http://stackoverflow.com/help/how-to-ask) section and always refer to the [Help Center](http://stackoverflow.com/help/asking).\n", "\n", "This is not meant to put you off in any way, but rather to let you know from the first moment what is the appropriate 'Netiquette' and accetable code of conduct that will make you stand out as competent programmer, even when you are asking for help." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Code (Applied Geo-example)\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If in the previous notebook we didn't even leave the U.K., this time we'll fly to the far away magical [Null Island](https://en.wikipedia.org/wiki/Null_Island).\n", "\n", "![null-islan](img/null-island.png)\n", "\n", "From its official government's [touristic office](http://www.nullisland.com/):\n", " \n", "> The Republic of Null Island\t \n", "> *LIKE NO PLACE ON EARTH!*\n", "\n", "In order to get there, you'll have to first solve the exercise, avoiding those pesky *Syntax Errors* and *Exceptions\"!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden", "solution2_first": true }, "outputs": [], "source": [ "longitude = ???(0.0)\n", "latitude ??? str(0.0)\n", "\n", "\n", "# King's College marker\n", "null_island = \"https://www.openstreetmap.org/?mlat=\"+???+\"&mlon=\"+longitude+\"#map=5/\"+latitude+\"/\"+longitude\n", " \n", "prnt null_island\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "solution2": "hidden" }, "outputs": [], "source": [ "longitude = str(0.0)\n", "latitude = str(0.0)\n", "\n", "\n", "# Null_island marker\n", "null_island = \"https://www.openstreetmap.org/?mlat=\"+latitude+\"&mlon=\"+longitude+\"#map=5/\"+latitude+\"/\"+longitude\n", "print(null_island)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To conclude: remember to always read the output, and try to understand what Python is telling you. You might learn a lot from these simple messages! " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Further references:\n", "\n", "\n", "For more information on the island you might watch this [short video](https://motherboard.vice.com/read/a-journey-to-the-center-of-null-island). \n", "\n", "If you are on Twitter, don't forget to follow the [Null Island buoy](https://twitter.com/NullIslandBuoy)!\n", "\n", "\n", "General list or resources\n", "- [Awesome list of resources](https://github.com/vinta/awesome-python)\n", "- [Python Docs](https://docs.python.org/2.7/tutorial/introduction.html)\n", "- [HitchHiker's guide to Python](http://docs.python-guide.org/en/latest/intro/learning/)\n", "- [Python for Informatics](http://www.pythonlearn.com/book_007.pdf)\n", "- [Learn Python the Hard Way](http://learnpythonthehardway.org/book/)\n", "- [CodeAcademy](https://www.codecademy.com/learn/python)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Credits!\n", "\n", "#### Contributors:\n", "The following individuals have contributed to these teaching materials: \n", "- [James Millington](https://github.com/jamesdamillington)\n", "- [Jon Reades](https://github.com/jreades)\n", "- [Michele Ferretti](https://github.com/miccferr)\n", "- [Zahratu Shabrina](https://github.com/zarashabrina)\n", "\n", "#### License\n", "The content and structure of this teaching project itself is licensed under the [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 license](https://creativecommons.org/licenses/by-nc-sa/4.0/), and the contributing source code is licensed under [The MIT License](https://opensource.org/licenses/mit-license.php).\n", "\n", "#### Acknowledgements:\n", "Supported by the [Royal Geographical Society](https://www.rgs.org/HomePage.htm) (with the Institute of British Geographers) with a Ray Y Gildea Jr Award.\n", "\n", "#### Potential Dependencies:\n", "This notebook may depend on the following libraries: None" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.10.5" } }, "nbformat": 4, "nbformat_minor": 4 }