{ "cells": [ { "cell_type": "markdown", "id": "cba03bar", "metadata": {}, "source": [ "\n", "**Other Ways to open this chapter:** \n", "[JupyterLite](https://python.porttack.com/jupyterlite-3db08322a4/notebooks/index.html?path=Chapter03-Functions.ipynb) | \n", "[Colab](https://colab.research.google.com/github/porttack/working-in-python/blob/v3/chapters/chap03.ipynb) | \n", "[Read Only](https://python.porttack.com/chap03.html?readonly) | \n", "Download\n", "\n", "" ] }, { "cell_type": "markdown", "id": "cba03pane", "metadata": {}, "source": [ "\n", "

Ignore this cell — used when running JupyterLite.

\n", "\n", "\n", "
\n", "\n", "
\n", "\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "103cbe3c", "metadata": { "tags": [] }, "outputs": [], "source": [ "from os.path import basename, exists\n", "\n", "def download(url):\n", " filename = basename(url)\n", " if not exists(filename):\n", " from urllib.request import urlretrieve\n", "\n", " local, _ = urlretrieve(url, filename)\n", " print(\"Downloaded \" + str(local))\n", " return filename\n", "\n", "download('https://github.com/porttack/working-in-python/raw/v3/working_in_python.py');\n", "download('https://github.com/AllenDowney/ThinkPython/raw/v3/diagram.py');\n", "\n", "import working_in_python" ] }, { "cell_type": "markdown", "id": "6bd858a8", "metadata": {}, "source": [ "# Functions\n", "\n", "In the previous chapter we used several functions provided by Python, like `int` and `float`, and a few provided by the `math` module, like `sqrt` and `pow`.\n", "In this chapter, you will learn how to create your own functions and run them.\n", "And we'll see how one function can call another.\n", "As examples, we'll display lyrics from Monty Python songs.\n", "These silly examples demonstrate an important feature -- the ability to write your own functions is the foundation of programming.\n", "\n", "This chapter also introduces a new statement, the `for` loop, which is used to repeat a computation." ] }, { "cell_type": "markdown", "id": "b4ea99c5", "metadata": {}, "source": [ "## Defining new functions\n", "\n", "A **function definition** specifies the name of a new function and the sequence of statements that run when the function is called. Here's an example:" ] }, { "cell_type": "code", "execution_count": null, "id": "d28f5c1a", "metadata": { "tags": [ "blank" ] }, "outputs": [], "source": [ "def print_lyrics():\n", " print(\"I'm a lumberjack, and I'm okay.\")\n", " print(\"I sleep all night and I work all day.\")" ] }, { "cell_type": "markdown", "id": "0174fc41", "metadata": {}, "source": [ "`def` is a keyword that indicates that this is a function definition.\n", "The name of the function is `print_lyrics`.\n", "Anything that's a legal variable name is also a legal function name.\n", "\n", "The empty parentheses after the name indicate that this function doesn't take any arguments.\n", "\n", "The first line of the function definition is called the **header** -- the rest is called the **body**.\n", "The header has to end with a colon and the body has to be indented. By convention, indentation is always four spaces. \n", "The body of this function is two print statements; in general, the body of a function can contain any number of statements of any kind.\n", "\n", "Defining a function creates a **function object**, which we can display like this." ] }, { "cell_type": "code", "execution_count": null, "id": "2850a402", "metadata": {}, "outputs": [], "source": [ "print_lyrics" ] }, { "cell_type": "markdown", "id": "12bd0879", "metadata": {}, "source": [ "The output indicates that `print_lyrics` is a function that takes no arguments.\n", "`__main__` is the name of the module that contains `print_lyrics`.\n", "\n", "Now that we've defined a function, we can call it the same way we call built-in functions." ] }, { "cell_type": "code", "execution_count": null, "id": "9a048657", "metadata": {}, "outputs": [], "source": [ "print_lyrics()" ] }, { "cell_type": "markdown", "id": "8f0fc45d", "metadata": {}, "source": [ "When the function runs, it executes the statements in the body, which display the first two lines of \"The Lumberjack Song\"." ] }, { "cell_type": "markdown", "id": "6d35193e", "metadata": {}, "source": [ "## Parameters\n", "\n", "Some of the functions we have seen require arguments; for example, when you call `abs` you pass a number as an argument.\n", "Some functions take more than one argument; for example, `math.pow` takes two, the base and the exponent.\n", "\n", "Here is a definition for a function that takes an argument." ] }, { "cell_type": "code", "execution_count": null, "id": "e5d00488", "metadata": {}, "outputs": [], "source": [ "def print_twice(string):\n", " print(string)\n", " print(string)" ] }, { "cell_type": "markdown", "id": "1716e3dc", "metadata": {}, "source": [ "The variable name in parentheses is a **parameter**.\n", "When the function is called, the value of the argument is assigned to the parameter.\n", "For example, we can call `print_twice` like this.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "a3ad5f46", "metadata": {}, "outputs": [], "source": [ "print_twice('Dennis Moore, ')" ] }, { "cell_type": "markdown", "id": "f02be6d2", "metadata": {}, "source": [ "Running this function has the same effect as assigning the argument to the parameter and then executing the body of the function, like this." ] }, { "cell_type": "code", "execution_count": null, "id": "042dfec1", "metadata": {}, "outputs": [], "source": [ "string = 'Dennis Moore, '\n", "print(string)\n", "print(string)" ] }, { "cell_type": "markdown", "id": "ea8b8b6e", "metadata": {}, "source": [ "You can also use a variable as an argument." ] }, { "cell_type": "code", "execution_count": null, "id": "8f078ad0", "metadata": {}, "outputs": [], "source": [ "line = 'Dennis Moore, '\n", "print_twice(line)" ] }, { "cell_type": "markdown", "id": "5c1884ad", "metadata": {}, "source": [ "In this example, the value of `line` gets assigned to the parameter `string`." ] }, { "cell_type": "markdown", "id": "a3e5a790", "metadata": {}, "source": [ "## Calling functions\n", "\n", "Once you have defined a function, you can use it inside another function.\n", "To demonstrate, we'll write functions that print the lyrics of \"The Spam Song\" ().\n", "\n", "> Spam, Spam, Spam, Spam, \n", "> Spam, Spam, Spam, Spam, \n", "> Spam, Spam, \n", "> (Lovely Spam, Wonderful Spam!) \n", "> Spam, Spam,\n", "\n", "We'll start with the following function, which takes two parameters.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "e86bb32c", "metadata": {}, "outputs": [], "source": [ "def repeat(word, n):\n", " print(word * n)" ] }, { "cell_type": "markdown", "id": "bdd4daa4", "metadata": {}, "source": [ "We can use this function to print the first line of the song, like this." ] }, { "cell_type": "code", "execution_count": null, "id": "ec117999", "metadata": {}, "outputs": [], "source": [ "spam = 'Spam, '\n", "repeat(spam, 4)" ] }, { "cell_type": "markdown", "id": "c6f81e09", "metadata": {}, "source": [ "To display the first two lines, we can define a new function that uses `repeat`." ] }, { "cell_type": "code", "execution_count": null, "id": "3731ffd8", "metadata": {}, "outputs": [], "source": [ "def first_two_lines():\n", " repeat(spam, 4)\n", " repeat(spam, 4)" ] }, { "cell_type": "markdown", "id": "8058ffe4", "metadata": {}, "source": [ "And then call it like this." ] }, { "cell_type": "code", "execution_count": null, "id": "6792e63b", "metadata": {}, "outputs": [], "source": [ "first_two_lines()" ] }, { "cell_type": "markdown", "id": "07ca432a", "metadata": {}, "source": [ "To display the last three lines, we can define another function, which also uses `repeat`." ] }, { "cell_type": "code", "execution_count": null, "id": "2dcb020a", "metadata": {}, "outputs": [], "source": [ "def last_three_lines():\n", " repeat(spam, 2)\n", " print('(Lovely Spam, Wonderful Spam!)')\n", " repeat(spam, 2)" ] }, { "cell_type": "code", "execution_count": null, "id": "9ff8c60e", "metadata": {}, "outputs": [], "source": [ "last_three_lines()" ] }, { "cell_type": "markdown", "id": "d6456a19", "metadata": {}, "source": [ "Finally, we can bring it all together with one function that prints the whole verse." ] }, { "cell_type": "code", "execution_count": null, "id": "78bf3a7b", "metadata": {}, "outputs": [], "source": [ "def print_verse():\n", " first_two_lines()\n", " last_three_lines()" ] }, { "cell_type": "code", "execution_count": null, "id": "ba5da431", "metadata": {}, "outputs": [], "source": [ "print_verse()" ] }, { "cell_type": "markdown", "id": "d088fe68", "metadata": {}, "source": [ "When we run `print_verse`, it calls `first_two_lines`, which calls `repeat`, which calls `print`.\n", "That's a lot of functions.\n", "\n", "Of course, we could have done the same thing with fewer functions, but the point of this example is to show how functions can work together." ] }, { "cell_type": "markdown", "id": "c3b16e3f", "metadata": {}, "source": [ "## Repetition\n", "\n", "If we want to display more than one verse, we can use a `for` statement.\n", "Here's a simple example.\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "29b7eff3", "metadata": {}, "outputs": [], "source": [ "for i in range(2):\n", " print(i)" ] }, { "cell_type": "markdown", "id": "bf320549", "metadata": {}, "source": [ "The first line is a header that ends with a colon.\n", "The second line is the body, which has to be indented.\n", "\n", "The header starts with the keyword `for`, a new variable named `i`, and another keyword, `in`. \n", "It uses the `range` function to create a sequence of two values, which are `0` and `1`.\n", "In Python, when we start counting, we usually start from `0`.\n", "\n", "When the `for` statement runs, it assigns the first value from `range` to `i` and then runs the `print` function in the body, which displays `0`.\n", "\n", "When it gets to the end of the body, it loops back around to the header, which is why this statement is called a **loop**.\n", "The second time through the loop, it assigns the next value from `range` to `i`, and displays it.\n", "Then, because that's the last value from `range`, the loop ends.\n", "\n", "Here's how we can use a `for` loop to print two verses of the song." ] }, { "cell_type": "code", "execution_count": null, "id": "038ad592", "metadata": {}, "outputs": [], "source": [ "for i in range(2):\n", " print(\"Verse\", i)\n", " print_verse()\n", " print()" ] }, { "cell_type": "markdown", "id": "88a46733", "metadata": {}, "source": [ "You can put a `for` loop inside a function.\n", "For example, `print_n_verses` takes a parameter named `n`, which has to be an integer, and displays the given number of verses. " ] }, { "cell_type": "code", "execution_count": null, "id": "8887637a", "metadata": {}, "outputs": [], "source": [ "def print_n_verses(n):\n", " for i in range(n):\n", " print_verse()\n", " print()" ] }, { "cell_type": "markdown", "id": "ad8060fe", "metadata": {}, "source": [ "In this example, we don't use `i` in the body of the loop, but there has to be a variable name in the header anyway." ] }, { "cell_type": "markdown", "id": "b320ec90", "metadata": {}, "source": [ "## Variables and parameters are local\n", "\n", "When you create a variable inside a function, it is **local**, which\n", "means that it only exists inside the function.\n", "For example, the following function takes two arguments, concatenates them, and prints the result twice." ] }, { "cell_type": "code", "execution_count": null, "id": "0db8408e", "metadata": {}, "outputs": [], "source": [ "def cat_twice(part1, part2):\n", " cat = part1 + part2\n", " print_twice(cat)" ] }, { "cell_type": "markdown", "id": "3a35a6d0", "metadata": {}, "source": [ "Here's an example that uses it:" ] }, { "cell_type": "code", "execution_count": null, "id": "1c556e48", "metadata": {}, "outputs": [], "source": [ "line1 = 'Always look on the '\n", "line2 = 'bright side of life.'\n", "cat_twice(line1, line2)" ] }, { "cell_type": "markdown", "id": "4ab4e008", "metadata": {}, "source": [ "When `cat_twice` runs, it creates a local variable named `cat`, which is destroyed when the function ends.\n", "If we try to display it, we get a `NameError`:\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "73f03eea", "metadata": { "tags": [] }, "outputs": [], "source": [ "\n", "print(cat)" ] }, { "cell_type": "markdown", "id": "3ae36c29", "metadata": {}, "source": [ "Outside of the function, `cat` is not defined. \n", "\n", "Parameters are also local.\n", "For example, outside `cat_twice`, there is no such thing as `part1` or `part2`." ] }, { "cell_type": "markdown", "id": "eabac8a6", "metadata": {}, "source": [ "## Stack diagrams\n", "\n", "To keep track of which variables can be used where, it is sometimes useful to draw a **stack diagram**. \n", "Like state diagrams, stack diagrams show the value of each variable, but they also show the function each variable belongs to.\n", "\n", "Each function is represented by a **frame**.\n", "A frame is a box with the name of a function on the outside and the parameters and local variables of the function on the inside.\n", "\n", "Here's the stack diagram for the previous example." ] }, { "cell_type": "code", "execution_count": null, "id": "83df4e32", "metadata": { "tags": [] }, "outputs": [], "source": [ "from diagram import make_frame, Stack\n", "\n", "d1 = dict(line1=line1, line2=line2)\n", "frame1 = make_frame(d1, name='__main__', dy=-0.3, loc='left')\n", "\n", "d2 = dict(part1=line1, part2=line2, cat=line1+line2)\n", "frame2 = make_frame(d2, name='cat_twice', dy=-0.3, \n", " offsetx=0.03, loc='left')\n", "\n", "d3 = dict(string=line1+line2)\n", "frame3 = make_frame(d3, name='print_twice', \n", " offsetx=0.04, offsety=-0.3, loc='left')\n", "\n", "d4 = {\"?\": line1+line2}\n", "frame4 = make_frame(d4, name='print', \n", " offsetx=-0.22, offsety=0, loc='left')\n", "\n", "stack = Stack([frame1, frame2, frame3, frame4], dy=-0.8)" ] }, { "cell_type": "code", "execution_count": null, "id": "bcd5e1df", "metadata": { "tags": [] }, "outputs": [], "source": [ "from diagram import diagram, adjust\n", "\n", "\n", "width, height, x, y = [3.77, 2.9, 1.1, 2.65]\n", "ax = diagram(width, height)\n", "bbox = stack.draw(ax, x, y)\n", "# adjust(x, y, bbox)\n", "\n", "import matplotlib.pyplot as plt\n", "plt.savefig('chap03_stack_diagram.png', dpi=300)" ] }, { "cell_type": "markdown", "id": "854fee12", "metadata": {}, "source": [ "The frames are arranged in a stack that indicates which function called\n", "which, and so on. Reading from the bottom, `print` was called by `print_twice`, which was called by `cat_twice`, which was called by `__main__` -- which is a special name for the topmost frame.\n", "When you create a variable outside of any function, it belongs to `__main__`.\n", "\n", "In the frame for `print`, the question mark indicates that we don't know the name of the parameter." ] }, { "cell_type": "markdown", "id": "5690cfc0", "metadata": {}, "source": [ "## Tracebacks\n", "\n", "When a runtime error occurs in a function, Python displays the name of the function that was running, the name of the function that called it, and so on, up the stack.\n", "To see an example, I'll define a version of `print_twice` that contains an error -- it tries to print `cat`, which is a local variable in another function." ] }, { "cell_type": "code", "execution_count": null, "id": "886519cf", "metadata": {}, "outputs": [], "source": [ "def print_twice(string):\n", " print(cat) # NameError\n", " print(cat)" ] }, { "cell_type": "markdown", "id": "d7c0713b", "metadata": {}, "source": [ "Now here's what happens when we run `cat_twice`." ] }, { "cell_type": "code", "execution_count": null, "id": "1fe8ee82", "metadata": { "tags": [] }, "outputs": [], "source": [ "# This cell tells Jupyter to provide detailed debugging information\n", "# when a runtime error occurs, including a traceback.\n", "\n", "%xmode Verbose" ] }, { "cell_type": "code", "execution_count": null, "id": "d9082f88", "metadata": { "tags": [] }, "outputs": [], "source": [ "\n", "cat_twice(line1, line2)" ] }, { "cell_type": "markdown", "id": "2f4defcf", "metadata": {}, "source": [ "The error message includes a **traceback**, which shows the function that was running when the error occurred, the function that called it, and so on.\n", "In this example, it shows that `cat_twice` called `print_twice`, and the error occurred in a `print_twice`.\n", "\n", "The order of the functions in the traceback is the same as the order of the frames in the stack diagram.\n", "The function that was running is at the bottom." ] }, { "cell_type": "markdown", "id": "374b4696", "metadata": {}, "source": [ "## Why functions?\n", "\n", "It may not be clear yet why it is worth the trouble to divide a program into\n", "functions.\n", "There are several reasons:\n", "\n", "- Creating a new function gives you an opportunity to name a group of\n", " statements, which makes your program easier to read and debug.\n", "\n", "- Functions can make a program smaller by eliminating repetitive code.\n", " Later, if you make a change, you only have to make it in one place.\n", "\n", "- Dividing a long program into functions allows you to debug the parts\n", " one at a time and then assemble them into a working whole.\n", "\n", "- Well-designed functions are often useful for many programs. Once you\n", " write and debug one, you can reuse it." ] }, { "cell_type": "markdown", "id": "c6dd486e", "metadata": {}, "source": [ "## Debugging\n", "\n", "Debugging can be frustrating, but it is also challenging, interesting, and sometimes even fun.\n", "And it is one of the most important skills you can learn.\n", "\n", "In some ways debugging is like detective work.\n", "You are given clues and you have to infer the events that led to the\n", "results you see.\n", "\n", "Debugging is also like experimental science.\n", "Once you have an idea about what is going wrong, you modify your program and try again.\n", "If your hypothesis was correct, you can predict the result of the modification, and you take a step closer to a working program.\n", "If your hypothesis was wrong, you have to come up with a new one.\n", "\n", "For some people, programming and debugging are the same thing; that is, programming is the process of gradually debugging a program until it does what you want.\n", "The idea is that you should start with a working program and make small modifications, debugging them as you go.\n", "\n", "If you find yourself spending a lot of time debugging, that is often a sign that you are writing too much code before you start tests.\n", "If you take smaller steps, you might find that you can move faster." ] }, { "cell_type": "markdown", "id": "d4e95e63", "metadata": {}, "source": [ "## Glossary\n", "\n", "**function definition:**\n", "A statement that creates a function.\n", "\n", "**header:**\n", " The first line of a function definition.\n", "\n", "**body:**\n", " The sequence of statements inside a function definition.\n", "\n", "**function object:**\n", "A value created by a function definition.\n", "The name of the function is a variable that refers to a function object.\n", "\n", "**parameter:**\n", " A name used inside a function to refer to the value passed as an argument.\n", "\n", "**loop:**\n", " A statement that runs one or more statements, often repeatedly.\n", "\n", "**local variable:**\n", "A variable defined inside a function, and which can only be accessed inside the function.\n", "\n", "**stack diagram:**\n", "A graphical representation of a stack of functions, their variables, and the values they refer to.\n", "\n", "**frame:**\n", " A box in a stack diagram that represents a function call.\n", " It contains the local variables and parameters of the function.\n", "\n", "**traceback:**\n", " A list of the functions that are executing, printed when an exception occurs." ] }, { "cell_type": "markdown", "id": "d922d83a", "metadata": {}, "source": [ "\n", "**See also:** the [full vocabulary glossary](https://python.porttack.com/alignment/ap-vocabulary-glossary.html) collects every term in this book, alphabetized, alongside the complete AP CSP exam vocabulary list.\n", "" ] }, { "cell_type": "markdown", "id": "eca485f2", "metadata": {}, "source": [ "## Exercises" ] }, { "cell_type": "code", "execution_count": null, "id": "3f77b428", "metadata": { "tags": [] }, "outputs": [], "source": [ "# This cell tells Jupyter to provide detailed debugging information\n", "# when a runtime error occurs. Run it before working on the exercises.\n", "\n", "%xmode Verbose" ] }, { "cell_type": "markdown", "id": "b7157b09", "metadata": {}, "source": [ "### Exercise\n", "\n", "Write a function named `print_right` that takes a string named `text` as a parameter and prints the string with enough leading spaces that the last letter of the string is in the 40th column of the display." ] }, { "cell_type": "code", "execution_count": null, "id": "a6004271", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "428fbee5", "metadata": {}, "source": [ "Hint: Use the `len` function, the string concatenation operator (`+`) and the string repetition operator (`*`).\n", "\n", "Here's an example that shows how it should work." ] }, { "cell_type": "code", "execution_count": null, "id": "f142ce6a", "metadata": { "tags": [] }, "outputs": [], "source": [ "print_right(\"Monty\")\n", "print_right(\"Python's\")\n", "print_right(\"Flying Circus\")" ] }, { "cell_type": "markdown", "id": "b47467fa", "metadata": {}, "source": [ "### Exercise\n", "\n", "Write a function called `triangle` that takes a string and an integer and draws a pyramid with the given height, made up using copies of the string. Here's an example of a pyramid with `5` levels, using the string `'L'`." ] }, { "cell_type": "code", "execution_count": null, "id": "7aa95014", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "b8146a0d", "metadata": { "scrolled": true, "tags": [] }, "outputs": [], "source": [ "triangle('L', 5)" ] }, { "cell_type": "markdown", "id": "4a28f635", "metadata": {}, "source": [ "### Exercise\n", "\n", "Write a function called `rectangle` that takes a string and two integers and draws a rectangle with the given width and height, made up using copies of the string. Here's an example of a rectangle with width `5` and height `4`, made up of the string `'H'`." ] }, { "cell_type": "code", "execution_count": null, "id": "bcedab79", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "73b0c0f6", "metadata": { "scrolled": true, "tags": [] }, "outputs": [], "source": [ "rectangle('H', 5, 4)" ] }, { "cell_type": "markdown", "id": "44a5de6f", "metadata": {}, "source": [ "### Exercise\n", "\n", "The song \"99 Bottles of Beer\" starts with this verse:\n", "\n", "> 99 bottles of beer on the wall \n", "> 99 bottles of beer \n", "> Take one down, pass it around \n", "> 98 bottles of beer on the wall \n", "\n", "Then the second verse is the same, except that it starts with 98 bottles and ends with 97. The song continues -- for a very long time -- until there are 0 bottles of beer.\n", "\n", "Write a function called `bottle_verse` that takes a number as a parameter and displays the verse that starts with the given number of bottles.\n", "\n", "Hint: Consider starting with a function that can print the first, second, or last line of the verse, and then use it to write `bottle_verse`." ] }, { "cell_type": "code", "execution_count": null, "id": "53424b43", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "61010ffb", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "ee0076dd", "metadata": { "tags": [] }, "source": [ "Use this function call to display the first verse." ] }, { "cell_type": "code", "execution_count": null, "id": "47a91c7d", "metadata": { "tags": [] }, "outputs": [], "source": [ "bottle_verse(99)" ] }, { "cell_type": "markdown", "id": "42c237c6", "metadata": { "tags": [] }, "source": [ "If you want to print the whole song, you can use this `for` loop, which counts down from `99` to `1`.\n", "You don't have to completely understand this example---we'll learn more about `for` loops and the `range` function later." ] }, { "cell_type": "code", "execution_count": null, "id": "336cdfa2", "metadata": { "tags": [] }, "outputs": [], "source": [ "for n in range(99, 0, -1):\n", " bottle_verse(n)\n", " print()" ] }, { "cell_type": "code", "execution_count": null, "id": "4b02510c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "2b3c4d5e", "metadata": {}, "source": [ "\n", "## Homework\n", "\n", "These five exercises are your homework for this chapter, about 33 minutes total.\n", "" ] }, { "cell_type": "markdown", "id": "6f7a8b9c", "metadata": {}, "source": [ "\n", "### Exercise 1: scope check\n", "\n", "Write a function called `set_mood` that takes a parameter `mood`, creates a local variable named `feeling` equal to `mood`, and prints `feeling`.\n", "\n", "Call `set_mood('excited')`. Then, in a new line below the call, try to `print(feeling)`.\n", "\n", "In a comment, explain what error you get and why -- what does the chapter's `cat` example (in the \"Variables and parameters are local\" section) have to do with what just happened here?\n", "" ] }, { "cell_type": "markdown", "id": "0d1e2f3a", "metadata": {}, "source": [ "\n", "### Exercise 2: read the traceback\n", "\n", "Run the cell below. It raises a `NameError`.\n", "\n", "1. In a comment, name all three functions in the call chain, in the order the traceback lists them.\n", "2. In a comment, say which one of the three was actually running when the error happened -- the other two just called it.\n", "3. Fix the bug (it's a typo) so the cell runs correctly.\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "extra-exercises-nameerror-buggy", "metadata": {}, "outputs": [], "source": [ "def announce(message):\n", " print(anouncement)\n", "\n", "def daily_update(topic):\n", " announce(topic)\n", "\n", "def morning_routine():\n", " daily_update('Good morning!')\n", "\n", "morning_routine()" ] }, { "cell_type": "markdown", "id": "4b5c6d7e", "metadata": {}, "source": [ "\n", "### Exercise 3: functions calling functions\n", "\n", "Write a function called `shout` that takes a parameter `word` and prints the word followed by `'!!!'`, using string concatenation from chapter 1.\n", "\n", "Then write a function called `greet` that takes a parameter `name` and calls `shout` to print a greeting that includes the name, the same way `print_verse` in the chapter called `first_two_lines` and `last_three_lines` instead of doing everything itself.\n", "" ] }, { "cell_type": "markdown", "id": "8f9a0b1c", "metadata": {}, "source": [ "\n", "### Exercise 4: math + functions review\n", "\n", "Remember the Pythagorean theorem exercise from chapter 2? Write a function called `show_hypotenuse` that takes two parameters, `a` and `b`, computes the hypotenuse using `math.sqrt` and `**` the same way you did there (remember to `import math` first), and prints a sentence with the result -- something like `The hypotenuse is 15.0`.\n", "\n", "Call it with a few different pairs of leg lengths to check that it works, including `9` and `12`.\n", "" ] }, { "cell_type": "markdown", "id": "2d3e4f5a", "metadata": {}, "source": [ "\n", "### Exercise 5: reflection\n", "\n", "Which do you think is more useful to you right now: functions calling other functions, or the `for` loop? Why?\n", "" ] }, { "cell_type": "markdown", "id": "extra-exercises-copy-heading", "metadata": {}, "source": [ "\n", "### Finished? Copy your work\n", "\n", "This isn't part of Exercise 5 -- it's a tool. Run the cell below to copy this notebook (including anything you've run) so you can paste it into a document.\n", "" ] }, { "cell_type": "code", "execution_count": null, "id": "extra-exercises-copy-button", "metadata": {}, "outputs": [], "source": [ "working_in_python.show_copy_notebook_button()" ] }, { "cell_type": "markdown", "id": "a7f4edf8", "metadata": { "tags": [] }, "source": [ "\n", "---\n", "\n", "**Working in Python** — modified by Eric Brown for a high school Computer Science Principles class. Source and modifications: [github.com/porttack/working-in-python](https://github.com/porttack/working-in-python)\n", "\n", "---\n", "\n", "\n", "[Think Python: 3rd Edition](https://allendowney.github.io/ThinkPython/index.html)\n", "\n", "Copyright 2024 [Allen B. Downey](https://allendowney.com)\n", "\n", "Code license: [MIT License](https://mit-license.org/)\n", "\n", "Text license: [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-nc-sa/4.0/)\n", "\n", "\n", "---\n", "\n", "## Standards alignment\n", "\n", "**AP CSP:** [3.12 Calling Procedures](https://python.porttack.com/alignment/apcsp-standards-reference.html#T-3.12), [3.13 Developing Procedures](https://python.porttack.com/alignment/apcsp-standards-reference.html#T-3.13) (Big Idea 3, 30–35% of the exam). [3.8 Iteration](https://python.porttack.com/alignment/apcsp-standards-reference.html#T-3.8) (the chapter's first `for` loop) and [1.4 Identifying and Correcting Errors](https://python.porttack.com/alignment/apcsp-standards-reference.html#T-1.4) also begin here, headers only.\n", "**California 9-12:** [9-12.AP.16](https://python.porttack.com/alignment/ca-cs-standards-reference.html#S-9-12.AP.16)\n", "**CSTA 2026:** [HS-PRO-PD-12](https://python.porttack.com/alignment/csta2026-standards-reference.html#T-HS-PRO-PD-12). Also [HS-PRO-RD-17](https://python.porttack.com/alignment/csta2026-standards-reference.html#T-HS-PRO-RD-17) and [HS-ALG-PS-02](https://python.porttack.com/alignment/csta2026-standards-reference.html#T-HS-ALG-PS-02), headers only.\n", "**CA CTE (ICT):** [C4.9](https://python.porttack.com/alignment/ca-ict-anchor-standards-reference.html#T-C4.9), [5.9](https://python.porttack.com/alignment/ca-ict-anchor-standards-reference.html#T-5.9) (Anchor Standard 5, Problem Solving). Also [5.10](https://python.porttack.com/alignment/ca-ict-anchor-standards-reference.html#T-5.10) and [C5.6](https://python.porttack.com/alignment/ca-ict-anchor-standards-reference.html#T-C5.6), headers only.\n", "\n", "This chapter's functions are the exam's procedures, same idea under a different name. Defining a function with parameters and calling it is exactly what 3.12, 3.13, and California's AP.16 ask for: breaking a problem into smaller, reusable pieces instead of solving it all in one place. Building `print_verse` out of smaller functions is also CSTA's HS-PRO-PD-12 and ICT's Anchor 5.9 in different words.\n", "\n", "**Vocabulary:** this book says *function*. The exam says *procedure*.\n", "" ] } ], "metadata": { "celltoolbar": "Tags", "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.11" } }, "nbformat": 4, "nbformat_minor": 5 }