{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# [CptS 111 Introduction to Algorithmic Problem Solving](https://github.com/gsprint23/cpts111)\n", "[Washington State University](https://wsu.edu)\n", "\n", "[Gina Sprint](http://eecs.wsu.edu/~gsprint/)\n", "# Debugging and Practice\n", "\n", "Learner objectives for this lesson\n", "* Understand how Python keeps track of program flow of execution with the call stack\n", "* Utilize basic features of a debugger" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "## Call Stack\n", "Recall that functions can call other functions. For example:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello from main()\n", "Hello from outer_function(). param_one: 0\n", "Hello from inner_function(). param_two: 1\n", "inner_function() return value: 2\n", "outer_function() return value: 3\n" ] } ], "source": [ "def inner_function(param_two):\n", " '''\n", " \n", " '''\n", " print(\"Hello from inner_function(). param_two: %d\" %(param_two))\n", " # 2 (1 + 1) will be copied into return_value in outer_function()\n", " return param_two + 1\n", "\n", "def outer_function(param_one):\n", " '''\n", " \n", " '''\n", " print(\"Hello from outer_function(). param_one: %d\" %(param_one))\n", " # 1 (0 + 1) will be copied into param_two in inner_function()\n", " return_value = inner_function(param_one + 1)\n", " print(\"inner_function() return value: %d\" %(return_value))\n", " # 3 (2 + 1) will be copied into return_value in main()\n", " return return_value + 1\n", " \n", "def main():\n", " '''\n", " \n", " '''\n", " print(\"Hello from main()\")\n", " # note this return_value variable is different than the return_value variable declared in outer_function\n", " # 0 will be copied into param_one in outer_function()\n", " return_value = outer_function(0) \n", " print(\"outer_function() return value: %d\" %(return_value))\n", "\n", "main()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When a statement in one function (e.g. `main()`) makes a call to another function (e.g. `outer_function()`), the execution of the calling function (e.g. `main()`) resumes once the execution of the called function (e.g. `outer_function()`) completes. As functions are called, Python keeps track of the order of function calls with the *call stack*. Here is an example for the above code:\n", "![](https://raw.githubusercontent.com/gsprint23/cpts111/master/lessons/figures/call_stack_example.png)\n", "\n", "The top most function on the call stack is the currently executing function. Once the top most function on the call stack finishes executing, execution returns to the calling function, and so on.\n", "\n", "Note: You can think of the call stack like a stack of plates in your cupboard: the first plate placed in the stack will be the last plate removed from the stack. A general *stack* (not necessarily a call stack), is a commonly used data structure in computer science. Many real-world problems can be solved using a stack data structure and its associated functions. Stacks will be covered in CptS 122 Data Structures :)\n", "\n", "## Program Crashes\n", "If an error occurs in your program, Python prints a *traceback* message to the console, which contains information about the state of the call stack when the program crashes:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'y' is not defined", "output_type": "error", "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[0;32m 11\u001b[0m \u001b[0mfunction_with_error\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0mmain\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;36mmain\u001b[1;34m()\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 10\u001b[0m '''\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mfunction_with_error\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m5\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 13\u001b[0m \u001b[0mmain\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[1;32m\u001b[0m in \u001b[0;36mfunction_with_error\u001b[1;34m(x)\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m '''\n\u001b[1;32m----> 5\u001b[1;33m \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[0m\u001b[0;32m 6\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mmain\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;31mNameError\u001b[0m: name 'y' is not defined" ] } ], "source": [ "def function_with_error(x):\n", " '''\n", " \n", " '''\n", " print(y)\n", " \n", "def main():\n", " '''\n", " \n", " '''\n", " function_with_error(5)\n", "\n", "main()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Debugging Your Program\n", "A *bug* is an error in your program. *Debugging* is the process of removing bugs from your program.\n", "\n", "How to debug your program:\n", "1. Use the debugger (demo to come)\n", "1. Insert print statements in your code (aka diagnostic calls)\n", " * Display intermediate results at critical points\n", " * Make sure everything actually is what you think it is (aka echo, aka sanity check)\n", "1. Use Google\n", " * Compile and runtime errors: often others have had these before you\n", " * Logic errors: make sure you truly understand the algorithm\n", "\n", "Note: if you use *anything* from Google (or anything that is not from the course materials or is not your own work), cite the source in a comment in your code.\n", "\n", "### Setting Debugger Breakpoints\n", "We can halt program execution at a specific line number in our code, this is called a *breakpoint.* In Spyder, double click in the gray side bar by the line you wish to place a breakpoint. A red dot representing the breakpoint will appear:\n", "![](https://raw.githubusercontent.com/gsprint23/cpts111/master/lessons/figures/setting_breakpoint.png)\n", "\n", "### Stepping Through Your Program\n", "Now, instead of running the program with the green play button (or F5), run the *Python debugger* (`pdb`) with the blue play/pause button (Ctrl + F5). The program will run until the breakpoint is reached, then it will pause. Now, you can step through the code line by line, stepping over functions (Ctrl + F10) or into functions (Ctrl + F11). There are also toolbar buttons to do this to the right of the debug play/pause button.\n", "\n", "As you step through your program, you can watch your variable values change in the Variable Explorer panel:\n", "![](https://raw.githubusercontent.com/gsprint23/cpts111/master/lessons/figures/variable_explorer.png)\n", "\n", "If you would like to learn more about debugging in Python, read about [`pdb`](https://docs.python.org/3/library/pdb.html) and check out this [`pdb` command cheatsheet](http://web.stanford.edu/class/physics91si/2013/handouts/Pdb_Commands.pdf)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Practice Problems (Re-worked Using Functions)\n", "Note: Some problem descriptions have been taken from Chapter 2 of Hanly & Koffman's Problem Solving and Program Design in C (7th Edition). For each problem define a `main()` function and use functions where appropriate!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem #1 Tax\n", "Write a program to compute the total price for a purchase after sales tax. Prompt the user to enter the purchase amount and the sales tax percent. Display the total price (to the nearest 2 decimal places) after adding the sales tax to the purchase amount.\n", "\n", "Use functions where appropriate!\n", "\n", "Example output:\n", "\n", "```\n", "Please enter the purchase price: 9.00\n", "Please enter the sales tax as a percent (%): 7.8\n", "Total purchase price after tax: $9.70\n", "```" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Please enter the purchase price: 9\n", "Please enter the sales tax as a percent: 7.8\n", "Total purchase price after tax: $9.70\n" ] } ], "source": [ "def get_purchase_price():\n", " '''\n", " \n", " '''\n", " \n", " user_price = float(input(\"Please enter the purchase price: \"))\n", " return user_price\n", "\n", "def get_sales_tax():\n", " '''\n", " \n", " '''\n", " user_tax_percent = float(input(\"Please enter the sales tax as a percent: \"))\n", " return user_tax_percent\n", "\n", "def compute_total_price(price_param, tax_percent_param):\n", " '''\n", " \n", " '''\n", " price_param += price_param * (tax_percent_param / 100)\n", " return price_param\n", "\n", "def display_total_price(total_param):\n", " '''\n", " \n", " '''\n", " print(\"Total purchase price after tax: $%.2f\" %(total_param))\n", " \n", "def main():\n", " '''\n", " \n", " '''\n", " purchase_price = get_purchase_price()\n", " tax_percent = get_sales_tax()\n", " total = compute_total_price(purchase_price, tax_percent)\n", " display_total_price(total)\n", "main()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem #2 Mileage Reimbursement\n", "Write a program that calculates mileage reimbursement for a salesperson at the rate of \\$.35 per mile. \n", "\n", "Use functions where appropriate!\n", "\n", "Example output:\n", "\n", "```\n", "MILEAGE REIMBURSEMENT CALCULATOR\n", "Please enter the beginning odometer reading: 13505.2\n", "Please enter the ending odometer reading: 13810.6\n", "You traveled 305.4 miles. At $0.35 per mile, your reimbursement is $106.89\n", "```" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Please enter the beginning odometer reading: 13505.2\n", "Please enter the ending odometer reading: 13810.6\n", "You traveled 305.4 miles. At $0.35 per mile, your reimbursement is $106.89\n" ] } ], "source": [ "def get_reading(label):\n", " '''\n", " \n", " '''\n", " odo = float(input(\"Please enter the %s odometer reading: \" %(label)))\n", " return odo\n", "\n", "def compute_difference(reading1, reading2):\n", " '''\n", " \n", " '''\n", " diff = reading2 - reading1\n", " return diff\n", " \n", "def compute_reimbursement(diff):\n", " '''\n", " \n", " '''\n", " reimb = diff * 0.35\n", " return reimb\n", "\n", "def display_reimbursement(diff, r):\n", " '''\n", " \n", " '''\n", " print(\"You traveled %.1f miles. At $0.35 per mile, your reimbursement is $%.2f\" %(diff, r))\n", " \n", "def main():\n", " '''\n", " \n", " '''\n", " r1 = get_reading(\"beginning\")\n", " r2 = get_reading(\"ending\")\n", " diff = compute_difference(r1, r2)\n", " reimb = compute_reimbursement(diff)\n", " display_reimbursement(diff, reimb)\n", "\n", "main()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Problem #3 Pythagoras\n", "The Pythagorean theorem states that the sum of the squares of the sides of a right triangle is equal to the square of the hypotenuse.\n", "\n", "$$side1^{2} + side2^{2} = hypotenuse^{2}$$\n", "\n", "For example, if two sides of a right triangle have lengths 3 and 4, then the hypotenuse must have a length of 5. Together the integers 3, 4, and 5 form a Pythagorean triple. There are an infinite number of such triples. Given two positive integers `m` and `n`, **where `m`> `n`**, a Pythagorean triple can be generated by the following formulas:\n", "1. side1 = $m^2 – n^2$\n", "1. side2 = $2mn$\n", "1. hypotenuse = $m^2 + n^2$\n", "\n", "Write a program that takes the values for `m` and `n` as input and displays the values of the Pythagorean triple generated by the formulas above.\n", "\n", "Use functions where appropriate!\n", "\n", "Example output:\n", "\n", "```\n", "Please enter an m value: 4\n", "Please enter an n value: 2\n", "Pythagorean triple: 12^2 + 16^2 = 20^2\n", "```" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Please enter an m value: 4\n", "Please enter an n value: 2\n", "Pytahgorean triple: 12^2 + 16^2 = 20^2\n" ] } ], "source": [ "def get_value(m_or_n):\n", " '''\n", " \n", " '''\n", " val = int(input(\"Please enter an %s value: \" %(m_or_n)))\n", " return val\n", "\n", "def compute_side1(m, n):\n", " '''\n", " \n", " '''\n", " side1 = m ** 2 - n ** 2\n", " return side1\n", "\n", "def compute_side2(m, n):\n", " '''\n", " \n", " '''\n", " side2 = 2 * m * n\n", " return side2\n", "\n", "def compute_hypotenuse(m, n):\n", " '''\n", " \n", " '''\n", " hypo = m ** 2 + n ** 2\n", " return hypo\n", "\n", "def display_triple(s1, s2, hypo):\n", " '''\n", " \n", " '''\n", " print(\"Pythagorean triple: %d^2 + %d^2 = %d^2\" %(s1, s2, hypo))\n", " \n", "def main():\n", " '''\n", " \n", " '''\n", " m = get_value(\"m\")\n", " n = get_value(\"n\")\n", " s1 = compute_side1(m, n)\n", " s2 = compute_side2(m, n)\n", " hypotenuse = compute_hypotenuse(m, n)\n", " display_triple(s1, s2, hypotenuse)\n", "main()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## MA7\n", "On a blank sheet of paper, write the following:\n", "1. Your full name (legibly please)\n", "1. Your TA name\n", "1. MA #7\n", "\n", "*Individually*, answer the following questions/problems:\n", "1. What about the design and implementation of functions is the *most* clear to you?\n", "1. What about the design and implementation of functions is the *least* clear to you?\n", "1. Of the topics that we have covered so far in CptS 111, which topics (if any) are you unclear about? Please be specific.\n", "1. Practice exam problem: Define and call a function that accepts 3 numeric parameters. The function computes and returns the average of the three numeric parameters. Display the returned result. Note: do not prompt for user input. Hard-code numeric arguments to your function.\n", "1. If the above problem was an exam question, how would you do? Perform a self-assessment." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7.09\n" ] } ], "source": [ "# problem #4 solution\n", "def compute_average(num1, num2, num3):\n", " '''\n", " \n", " '''\n", " avg = (num1 + num2 + num3) / 3\n", " return avg\n", " \n", "# do not prompt for user input\n", "# hard code values (make up any 3 values to test the program)\n", "average = compute_average(-3.4, 5.68, 19)\n", "print(\"%.2f\" %(average))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## TODO\n", "1. Work on PA2.\n", "2. Read in zyBooks and How to Think Like a Computer Scientist about functions and conditionals (`if` statements).\n", "\n", "## Next Lesson\n", "We start conditionals!" ] } ], "metadata": { "anaconda-cloud": {}, "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.7.1" } }, "nbformat": 4, "nbformat_minor": 1 }