{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "

\n", "✅ **Put Your Name Here**\n", "

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Day {} Pre-Class Assignment - Debugging" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Goals for today's pre-class assignment\n", "\n", "* *Students are learning about some computational tool, and Learning about the basics of functional programming in Python and computational tools (i.e., variables and types, functions, simple data structures, strings, lists, tuples)*: Learning more about functions, how to handle and correct Python errors\n", "* *Students are thinking about modeling as a practice*: Learning the process of debugging code and looking for, not only errors, but also unexpected behavior and what it means to be \"correct\" in terms of output, searching for resources when code is not working" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**This assignment is due by 11:59 p.m. the day before class,** and should be uploaded into the \"Pre-Class Assignments\" dropbox folder for Day {}. Submission instructions can be found at the end of the notebook." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The goal of this assignment is to give you much more practice working through bugs in code and engaging in the debugging process." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import random\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Debugging is a large portion of programming. Often times when you are working on a computational project, you are going to end up devoting a lot of time to debugging your code, which is to say you will encounter issues where your code is either broken (returning an error message) or is not behaving the way that you want it to behave. The process of debugging is highly abstract: there is no \"conrete, for-sure method\". Everyone has their own way of figuring out issues in their code. We would like to give you an idea as to *some* of the ways that we feel are most effective for *identifying* and *correcting* bugs in your code. For this reason, we have developed our own instructional video on debugging. This is so we can focus not on specific ways to debug (e.g. using pdb or a built in debugging tool in software such as Spyder or Pycharm). " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from IPython.display import YouTubeVideo\n", "YouTubeVideo(\"TSWXvhAy2Wc\",width=640,height=360)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Question:** What is debugging? What are the steps that we recommend for how to alleviate frustration and issues that are caused by software bugs?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fortunately, some bugs are obvious based on the error message. By obvious, we are referring to the fact that the error message gives you close to enough information to be able to not only figure out *where* the code broke, but also *why* the code broke. This is critical to the debugging process. We first need to identify where the bug occured: what line it occured in what section of the code (and when the projects become large, which file contains the bug). Let's consider the example below. We first defined a string, \"Joe\", and then we tried to divide it by 3. Maybe we were thinking that since \"Joe\" has three letters in it, that by dividing it by 3, we could get a list of the letters individually." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "name = \"Joe\"\n", "name/3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The error message did not tell us which line the error occurred in (it does not give a line number), but in the error message, it indicates with an arrow where the error occurred. But, it does tell us that there is a TypeError. This is an error that a program throws when you are trying to do something to a specific kind of data that python doesn't know how to handle. In this case, /: 'str' and 'int'. Python doesn't know how to \"divide\" a string by 3. Here, we had enough information to be able to identify the problem and seek to fix it. And by doing a google search, we found that if we wanted to split the string into letters, we just make it into a list like so" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "list(name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And now we don't need to divide the name by 3. Getting a TypeError typically means you're trying to do something that Python doesn't know how to mathematically or organizationally handle. Another example of this is with a list" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "this_list = [1,2,3]\n", "this_list + 4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, maybe we were trying to add 4 onto the end of the list using addition rather than the append method. Or, perhaps we were remembering that the addition sign, when used between two lists, concatenates them into a longer list. But, the way we have currently written the code, Python is being told to add the number 4 and a collection of numbers (1, 2, and 3). Since it doesn't know how to perform this operation, it throws and error message." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other times, the errors are much less clear and more difficult to understand exactly *what* is wrong. Take this example." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 0 \n", "\n", "for i in range(10):\n", " x = x + i\n", " print((x+i+2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At first glance, \"unexpected EOF while parsing\" doesn't seem to offer a whole lot in terms of figuring out what is wrong. But, python tells you where the error is. Having line numbers may help for this process. To turn on line numbers in a cell, click on the cell and hit Esc-l (that is escape - L, but the L is lowercase). Going to line 5, we see that we have an open parenthesis for print, we didn't \"close\" our print statement. So, python reached the end of the line and expected to see a closing parenthesis, but didn't. So, the error was thrown. This can also be an \"EOL\" error like the following " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This time we forgot a quotation mark. For EOF/EOL errors, *most* of the time, it is a result of a missing quotation, parenthesis, etc. We say \"most\" of the time because there's always going to be one case where the general rule doesn't apply. But, the point we are trying to make here is that Python did not say \"you have a missing parenthesis or a missing quotation mark\", which means that we had to be observant and **look** for the part of the code that was misssing. Sometimes, programming results in error messages that give zero information. In instances like that, strategies that provide insight into the working of the code (e.g. [print statements](https://pythondebugging.com/articles/python-debugging-with-print-statements), or using [pdb](https://docs.python.org/3/library/pdb.html)) are going to be the best bet. The less information you get from Python when an error is throw, the more work you will have to do to figure out what is causing the error." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "SyntaxError's are very common in programming. A SyntaxError just means that whatever piece of code you wrote wasn't written correctly. This could be due to something like a comma in an undesired location, a stray decimal point after hastily typing a line, etc. These errors are usually quick to identify, such as these." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print.(5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for, i in range(5):\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Other times, we get a peak into the picky nature of Python. Say, for example, that we wanted to set up an if/else block to determine what to print for a given input. The condition for being a \"Small number\" is equal to or less than 20. We write the following code to determine this" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 10\n", "\n", "if x =< 20:\n", " print(\"Small Number\")\n", "else:\n", " print(\"Big Number\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We know that something is wrong, but what could it be. Mathematically, the statement is correct. But Python is unhappy because we typed the equal sign first. If we switch the \"=\" and the \"<\" symbols, the code will work fine." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 10\n", "\n", "if x <= 20:\n", " print(\"Small Number\")\n", "else:\n", " print(\"Big Number\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These examples may seem simple compared to the ones that you may or may not have encountered in class, but the goal of this assignment is not to show you incredibly complicated syntax filled with hard to decipher errors. The goal of this assignment is to show you that Python is a complex language with many opportunities for error and varying levels of specificity as to where/what the error is. Understanding these concepts at a basic level are going to be helpful in providing you with some skills for how to go about debugging your own projects. No matter the size of the project, big or small, the actions needed to fix the bug are generally the same (in terms of these kinds of errors, we will get to some more complicated errors soon). Let's continue with another example. We've used logic in if/else statements before, but it doesn't always work the way we want it to, specifically when we talk about objects such as lists and arrays." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 10\n", "\n", "if x < 20 and x > 8:\n", " print(\"Medium Number\")\n", "else:\n", " print(\"Meh\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we have seen working with numpy in class, we can use logical functions to \"mask\", or filter, our data." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.array([1,2,3,4,5,6,7,8,9,10,11,12])\n", "x[x > 3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That's using a single logical functino to mask the array and return only values that are greater than 3. But, watch what happens when we try and use an and statement. We would expect to get a range of values between 3 and 8 to be returned." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x[x > 3 and x < 8]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is one of those Python errors that doesn't shed much light onto our issue. What we mean by that is that there is no clear fix to the problem (e.g. \"you can't use that statement here\", \"invalid syntax\", or \"operation not allowed\" type errors). Whenever you encounter errors such as this, then it's always good to copy and paste the error into google and see what search results you get. Chances are, if you're getting an error trying to do something in Python, someone else has tried to do it before and gotten a similar error. As an exercise, try searching this error and seeing what you get." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's why that combination of logical doesn't work. Remember how we did the original masking. Let's break this down to dissect the problem. The first step to debugging should always be to figure out where the issue in the code is. So, we are going to start with the stuff inside of the square brackets, x > 3 and x < 8." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x > 3 and x < 8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It appears that the code is still broken (throwing an error), so we will now split the statement up and see *specifically* where in this line of code the issue is. This need for further exploration is also because the error that python gave us still isn't very useful." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x > 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just to review, the way that numpy uses this is that it only keep values of x for which the corresponding element is True. What does that mean. Well, if we compared x and the return value for x > 3 (both of which are arrays), then we can quickly get a sense of how numpy is working in the background" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_bool = x > 3\n", "for i in range(len(x>3)):\n", " print(\"x[{}] = {}. \\tx > 3 [{}] = {}\".format(i, x[i], i, x_bool[i]))\n", "print(\"Result: \", x[x_bool])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looking at these side by side, we see that numpy tries and matches the True values to the values in x. As a result, we get all of the original values great than 3. We have also, in this process, determined that this part of the code is not what is wrong. Since x > 3 didn't result in an error, then we can deduce that x < 8 shouldn't either. But just to be sure, let's prove it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x[x < 8]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Good, we aren't crazy. So, the bug **has** to be caused by the and statement because each individual asepct of the code (i.e. x > 3, x < 8, and x[x > 3] / x[ x < 8]) run as we expect without throwing any errors. This is a key concept in debugging: sometimes you have to dissect your code down to this level when the issues aren't glaringly obvious." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x > 3 and x < 8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There's the error, just as we have come to expect it! But, we still don't know what the problem is. We have used logical statements before. This should work." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Question:** What does ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() mean? What kinds of search results did you get? What do you think is the solution to the error? Try fixing the code to only given a range of value between 3 and 8. (Hint: trying googling what the & symbol does with arrays in Python)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Examples**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The cells below each contain code that, when run, will throw an error. For each of the following:\n", "1. Describe what you think the code *should* be doing\n", "2. What error message are you getting? What does that error message mean?\n", "3. How could the code be corrected so that it will run without throwing an error *and* perform the task that you think it should be?\n", "4. Try copying and pasting the code into a new cell and correcting it as you outlined in the above question.\n", "\n", "Be sure to answer all of the questions for each piece of code." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "B = [range(100)]\n", "B" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##You may need to google the formula for standard deviation if it's something that you aren't familiar with\n", "##But knowledge of the formula is not required to fix the bug\n", "def mean_and_standard_deviation(data):\n", " mean = sum(data)/len(data)\n", " variance = 0\n", " for entry in data:\n", " variance += (data - mean)**2\n", " variance /= len(data)\n", " return mean, variance **(1/2)\n", "\n", "D = [3.2, 7.8, 1.11, 10.98, 13.4, 8.8]\n", "\n", "mean_and_standard_deviation(D)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "num = 407\n", "if num > 1:\n", " for i in range(2,num):\n", " if (num % i) = 0:\n", " print(num,\"is not a prime number\")\n", " print(i,\"times\",num//i,\"is\" num)\n", " break\n", " else:\n", " print(num \"is a prime number\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have thus far only looked at bugs that break code. Before moving on to the remainder of this assignment, **watch the following video about an example of a different kind of bug that can be found in code**. There are no questions to answer on this video, but watching it will help to prepare you for the remainder of the assignment." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "YouTubeVideo(\"UZDmJsib05Q\", width = 640, height = 360)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Not all bugs break code!** A big part of debugging code has to do, not necessarily with fixing syntax issues or searching for missing parenthesis, but in looking for where the code has been *written* incorrectly. This seems convoluted, so let's discuss it. Often times, code is not broken in the sense that it will not run without throwing an error like the work we have done up until this point. Instead, code will break in the sense that it runs, but the output is not what you would expect. Another way of saying that is that the code was *written* improperly (either based on programmer error or a misunderstanding of how a tool operates) and now has a bug in it. The bug be thought of as some mischevious error that's hiding away in your many lines of code and causing you all sorts of troubles. These bugs are often **much more difficult** to track down and correct. Why? Because at least when something breaks, Python tells you where the breaking is occurring. But, when your code doesn't run the way that it should, python doesn't say anything because the code ran and that was its directive. This goes back to a saying as old as computers which is, \"Computers are dumb because they do exactly what you tell them to.\" The cause of the error is almost certainly due to how you typed your program. **That's perfectly okay though!** Making mistakes and learning from those mistakes is all a part of learning. That applies no matter what you are studying or what you are working on. It may, at this time, be helpful to try and consider an example. A lot of you have probably experienced this issue where your code seems to run forever in the background. To avoid any issues with crashing your computer, the code will be inline text as opposed to an executeable cell." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Example:**\n", "python\n", "total = 0\n", "a = 1\n", "\n", "while a <= 100:\n", " total += a\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Question:** If we were to run this code, it would never stop running and may crash our computers. **BUT**, it will not throw an error message. Why is this so? Why do you think this happens so commonly? What sort of precautions can you use to prevent these issues from happening in your code?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is one of the reasons why while loops can be both incredibly effective, and also very dangerous. Always check to make sure that, at some point, the logical statement that determines how long the loop will run for, can actually occur. Another common place where these errors occur are with functions. This is starting to get into some specifics of programming, but this concept is very important to udnerstand as you start writing more complex code and including more compartmentalization (writing functions) in your work. Let's discuss this through an example." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def subtraction(num1, num2):\n", " print(abs(num1 - num2))\n", " \n", "x = subtraction(10, 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Above we have a simple function which just takes the magnitude of the difference between two numbers. And, when we run the cell, we see that subtraction(10, 2) spits out the rest of 8. At the very least, our math is correct. Let's say now that we wanted to use this result for some further computation, so we store it in a value x. And, later on in the code we need to double that number (e.g. whatever model we are working with specifically cares about twice the difference between two numbers)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x*2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What is a 'NoneType'? Well, it turns out (and this is where the programming specific stuff is coming into play), that since we did not give a return statement to our function, then the function gives us \"nothing\" (or a 'NoneType') as a result. Let's look at the function carefully again. We take in two numbers, num1 and num2, and we *print* the absolute value of the difference. The keyword there is print. When something is printed using a print statement, nothing happens to that information anymore. Python takes whatever arguments you put into the print function, outputs them to the screen, and then forgets about that input. If we want an end value *out of the function*, we have to make sure that we use a return statement. You can think of this in a couple of ways. First, a return statement is like a return on investment: you give the function something and the function gives you something back just like (one would hope) putting money into an investment getting a different amount of money back out. Another way you can think about it, which is slightly different, is that you can think about the function sort of like a variable. When we want the variable to have a value stored in it, we say something like variable = 10. But, if we just say variable, then what happens?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "variable" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We haven't ever given something named \"variable\" contents (e.g. a number or an array, etc.). So Python says, \"I don't know what that means, you've never told me about variable.\" The same is, sort of, true with functions. If we don't give the function a return value, then it's like not defining a variable. Except, with functions, instead of throwing an error, Python assigns what is called a 'NoneType', which basically means that the function doesn't give you anything back in return. If we change the print statement to a return statement, this should work the way we want it to." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def subtraction(num1, num2):\n", " return abs(num1 - num2)\n", " \n", "x = subtraction(10, 2)\n", "x*2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The other tricky thing with functions is often what is called \"scope\". Now, this is somewhat more programming-focused than we like to be in this course. Essentially, scope can be thought of as where you define the variables and where those names apply. We are used to defining variables and using them in the scope of the entire notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want to use the variable A now, we just make a call to it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes, however, variables get defined in other scopes. Take our next function for instance. The input is a single number and the output is just twice that number. But, let's say that we first calculate the product of the input number and 2 and store it as a variable var. That variable is then returned by the function. But, what does this all mean in terms of scope?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def double_number(num):\n", " val = num*2\n", " return val\n", "\n", "y = double_number(2)\n", "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We see that the function did indeed return the value of var. But, can we reference var now that we have run the cell? It was, after all, the return value of the function, which we just learned about." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(val)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You may be thinking, \"Now hold on a second. We just talked about how return is how you get a value back out of a function. And there's a return statement. **And** I can see right there where var is defined. Why doesn't this work?\" The answer is scope. We defined var *inside of the function*. So, we can only reference var in the scope that it is defined in. That's to say, we can only use it inside of the function where we declared it. This is where functions can get a little tricky. If you define a variable inside of a function, you can only use it inside of that function. return doesn't give you the variable itself as the return value (it's name and associated value), it give you *just the value*. So, when you are working with functions, be sure to use care in **where** you define your variables and **how** you are using them." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's take a look at something that isn't functions now. The following code uses the input command to get the user to enter two numbers. The numbers then get run through a function, add, which adds them together. The result of the sum is printed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "number_1 = input(\"Enter a number: \")\n", "number_2 = input(\"Enter a second number: \")\n", "\n", "def add(num1, num2):\n", " return num1 + num2\n", "\n", "print(\"Sum is: \", add(number_1, number_2))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we didn't get an error, which means Python knew exactly what to do with this. BUt $10 + 1 \\neq 101$. \n", "\n", "**Question:** Why did the code print an incorrect sum? Can you change the code to properly add the numbers together?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a prime example of how code doesn't have to break to be broken. The code *runs*, but it doesn't *run* correctly, and it's ultimately due to the fact that we just didn't type our syntax out correctly, or we made a math error like we did in the following example. We wrote a function which sums up all of the digits below a certain threshold, namely sum_digits_below = $\\sum_{0}^{N} N$. We then tested it by summing all of the digits less than or equal to 10. We made use of numpy in our function as well using the [linspace method](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html). " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def sum_digits_below(num):\n", " return np.linspace(0, num, num).sum()\n", "\n", "sum_digits_below(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Seems to be a decent result. At first glance, it's tempting to say that our code is working just fine and not to worry about a thing. But, just because we are paranoid, let's actually check the answer manually (a good thing to *always* do when writing programs, especially more complex ones)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "0+1+2+3+4+5+6+7+8+9+10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Well... code is not breaking, but it definitely isn't mathematically correct. How are we off by so much?\n", "\n", "**Question:** What is wrong with the above code? Try using some of the things that you have learned about debugging in this notebook to dissect this code and figure out where the problem is, and then try and fix it yourself. What are two takeaways from this example?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Examples**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The cells below each contain code that will run, but the result will not be correct (broken but not breaking). For each of the examples:\n", "1. Describe what you think the code *should* be doing.\n", "2. How do you know that the result of the code is incorrect?\n", "3. How could the code be corrected so that it will run as expect it to?\n", "4. Try copying and pasting the code into a new cell and correcting it as you outlined in the above question.\n", "\n", "Be sure to answer all of the questions for each piece of code." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "num = 32\n", "if num > 1:\n", " for i in range(1,num):\n", " if (num % i) == 0:\n", " print(num,\"is not a prime number\")\n", " print(i,\"times\",num//i,\"is\", num)\n", " break\n", " else:\n", " print(num, \"is a prime number\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def factorial(num):\n", " factorial = 0\n", " for i in range(1, num + 1):\n", " factorial = factorial + i\n", " print(\"{}! = {}\".format(num, factorial))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "factorial(2)\n", "factorial(3)\n", "factorial(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " Do This - Erase the contents of this cell and replace it with your answer to the above question! (double-click on this text to edit this cell, and hit shift+enter to save the text)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "##Put your code here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## **Summary:**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Step 1: Where is the bug occuring?\n", "\n", "When you encounter an error in your code, you want to make sure you look at the very end of the error output to determine exactly what the error is. Then, in order to actually fix the error, you first need to figure out where it is happening. When the code produces an error, Python creates a \"Traceback\" which shows exactly what parts of the program ran into problems. The first part of Traceback actually tells you what line in the code that you wrote is causing the error, so once you understand what the error is, you'll want to look at the very top of the error output to figure out which line started all of the trouble. You should get into the habit of carefully reading the Python error messages because they are trying to help you! This can be much more complicated when Python doesn't throw an error message, which leads to a much more involved process. The solution when no error message is read is a line-by-line check: read through each line of code, udnerstand what it is doing, and then formulate a conclusion from there.\n", "\n", "### Step 2: What is causing the bug?\n", "The second step in our debugging process is to figure out what is causing the bug. If the error doesn't provide much insight, try copying the error message into a search bar and seeing what results are. From there, the process is, as we outlined in this notebook, honing in on the specific line of code that's broken and dissecting it into pieces. What is the *exact* thing that is causing the issue? Again, much more difficult when there is no error message to work off of.\n", "\n", "### Step 3: How do you fix the bug? (Putting it all together)\n", "Once you know where the bug is and what is causing the bug, then you can start taking measures to crrect it. **Don't try and change random lines of code. You may end up breaking something that wasn't in the first place.** You shouldn't even attempt to fix a bug until you know what the bug *is*. \"If it ain't broke, don't fix it.\"\n", "\n", "Debugging is a complicated and often very time consuming process. It's natural to get frustrated with it! Even expert programmers spend large amounts of time debugging their code and searching out places where something has gone wrong. It is always okay to ask for help when something isn't going right. Just remember to do this in the correct way: copying and pasting your entire project onto a discussion board or slack channel is probably not the best way to have a conversation about a bug. You should insead: 1. Outline what you are trying to do in your code, 2. Paste the portion of the code that isn't working properly, 3. What you expected the code to give you if it were working, and 4. What the code is actually giving you.\n", "\n", "This is something that, the more you code, the more comfortable you are going to be with finding issues and correcting them. Don't let a bug discourage you! Even billion dollar corporations have to [fix bugs](https://gulfnews.com/guides/tech/apple-releases-fix-for-telugu-bug-that-crashes-iphones-1.2176310) all the time! The important part about this whole process is that you continue trying. Bugs will happen, but they don't spell the end of a good idea or a great project." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python [default]", "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.5.4" } }, "nbformat": 4, "nbformat_minor": 2 }