# 6. Functions ## 6.1. Functions In Python, a **function** is a named sequence of statements that belong together. Their primary purpose is to help us organize programs into chunks that match how we think about the solution to the problem. The syntax for a **function definition** is: ```python def name( parameters ): statements ``` You can make up any names you want for the functions you create, except that you can’t use a name that is a Python keyword, and the names must follow the rules for legal identifiers that were given previously. The parameters specify what information, if any, you have to provide in order to use the new function. Another way to say this is that the parameters specify what the function needs to do its work. There can be any number of statements inside the function, but they have to be indented from the `def`. In the examples in this book, we will use the standard indentation of four spaces. Function definitions are the second of several **compound statements** we will see, all of which have the same pattern: 1. A header line which begins with a keyword and ends with a colon. 2. A **body** consisting of one or more Python statements, each indented the same amount – *4 spaces is the Python standard* – from the header line. We’ve already seen the `for` loop which follows this pattern. In a function definition, the keyword in the header is `def`, which is followed by the name of the function and some *parameters* enclosed in parentheses. The parameter list may be empty, or it may contain any number of parameters separated from one another by commas. In either case, the parentheses are required. We need to say a bit more about the parameters. In the definition, the parameter list is more specifically known as the **formal parameters**. This list of names describes those things that the function will need to receive from the user of the function. When you use a function, you provide values to the formal parameters. The figure below shows this relationship. A function needs certain information to do its work. These values, often called **arguments** or **actual parameters**, are passed to the function by the user.  This type of diagram is often called a **black-box diagram** because it only states the requirements from the perspective of the user. The user must know the name of the function and what arguments need to be passed. The details of how the function works are hidden inside the “black-box”. Suppose we’re working with turtles and a common operation we need is to draw squares. It would make sense if we did not have to duplicate all the steps each time we want to make a square. “Draw a square” can be thought of as an *abstraction* of a number of smaller steps. We will need to provide two pieces of information for the function to do its work: a turtle to do the drawing and a size for the side of the square. We could represent this using the following black-box diagram.  Here is a program containing a function to capture this idea. Give it a try. ```python import turtle def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") alex = turtle.Turtle() # create alex drawSquare(alex, 50) # Call the function to draw the square passing the actual turtle and the actual side size wn.exitonclick() ``` This function is named `drawSquare`. It has two parameters — one to tell the function which turtle to move around and the other to tell it the size of the square we want drawn. In the function definition they are called `t` and `sz` respectively. Make sure you know where the body of the function ends — it depends on the indentation and the blank lines don’t count for this purpose! docstrings If the first thing after the function header is a string (some tools insist that it must be a triple-quoted string), it is called a **docstring** and gets special treatment in Python and in some of the programming tools. Another way to retrieve this information is to use the interactive interpreter, and enter the expression `
.__doc__`, which will retrieve the docstring for the function. So the string you write as documentation at the start of a function is retrievable by python tools *at runtime*. This is different from comments in your code, which are completely eliminated when the program is parsed. By convention, Python programmers use docstrings for the key documentation of their functions. Defining a new function does not make the function run. To do that we need a **function call**. This is also known as a **function invocation**. We’ve already seen how to call some built-in functions like `print`, `range` and `int`. Function calls contain the name of the function to be executed followed by a list of values in parentheses, called *arguments*, which are assigned to the parameters in the function definition. So in the second to the last line of the program, we call the function, and pass `alex` as the turtle to be manipulated, and 50 as the size of the square we want. Once we’ve defined a function, we can call it as often as we like and its statements will be executed each time we call it. In this case, we could use it to get one of our turtles to draw a square and then we can move the turtle and have it draw a different square in a different location. Note that we lift the tail so that when `alex` moves there is no trace. We put the tail back down before drawing the next square. Make sure you can identify both invocations of the `drawSquare` function. ```python import turtle def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") alex = turtle.Turtle() # create alex drawSquare(alex, 50) # Call the function to draw the square alex.penup() alex.goto(100,100) alex.pendown() drawSquare(alex,75) # Draw another square wn.exitonclick() ``` In the next example, we’ve changed the `drawSquare` function a little and we get `tess` to draw 15 squares with some variations. Once the function has been defined, we can call it as many times as we like with whatever actual parameters we like. ```python import turtle def drawMulticolorSquare(t, sz): """Make turtle t draw a multi-colour square of sz.""" for i in ['red','purple','hotpink','blue']: t.color(i) t.forward(sz) t.left(90) wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") tess = turtle.Turtle() # create tess and set some attributes tess.pensize(3) size = 20 # size of the smallest square for i in range(15): drawMulticolorSquare(tess, size) size = size + 10 # increase the size for next time tess.forward(10) # move tess along a little tess.right(18) # and give her some extra turn wn.exitonclick() ``` Warning Even if a function call needs no arguments, the parentheses `( )` after the function name are *required*. This can lead to a difficult bug: A function name without the parenthesis is a legal expression *referring* to the function; for example, `print` and `alex.penup`, but they do not *call* the associated functions. Note This workspace is provided for your convenience. You can use this activecode window to try out anything you like. **Check your understanding** What is a function in Python? * A named sequence of statements. * Yes, a function is a named sequence of statements. * Any sequence of statements. * While functions contain sequences of statements, not all sequences of statements are considered functions. * A mathematical expression that calculates a value. * While some functions do calculate values, the python idea of a function is slightly different from the mathematical idea of a function in that not all functions calculate values. Consider, for example, the turtle functions in this section. They made the turtle draw a specific shape, rather than calculating a value. * A statement of the form x = 5 + 4. * This statement is called an assignment statement. It assigns the value on the right (9), to the name on the left (x). What is one main purpose of a function? * To improve the speed of execution * Functions have little effect on how fast the program runs. * To help the programmer organize programs into chunks that match how they think about the solution to the problem. * While functions are not required, they help the programmer better think about the solution by organizing pieces of the solution into logical chunks that can be reused. * All Python programs must be written using functions * In the first several chapters, you have seen many examples of Python programs written without the use of functions. While writing and using functions is desirable and essential for good programming style as your programs get longer, it is not required. * To calculate values. * Not all functions calculate values. Which of the following is a valid function header (first line of a function definition)? * def drawCircle(t): * A function may take zero or more parameters. It does not have to have two. In this case the size of the circle might be specified in the body of the function. * def drawCircle: * A function needs to specify its parameters in its header. * drawCircle(t, sz): * A function definition needs to include the keyword def. * def drawCircle(t, sz) * A function definition header must end in a colon (:). What is the name of the following function? ```python def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) ``` * def drawSquare(t, sz) * This line is the complete function header (except for the semi-colon) which includes the name as well as several other components. * drawSquare * Yes, the name of the function is given after the keyword def and before the list of parameters. * drawSquare(t, sz) * This includes the function name and its parameters * Make turtle t draw a square with side sz. * This is a comment stating what the function does. What are the parameters of the following function? ```python def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) ``` * i * i is a variable used inside of the function, but not a parameter, which is passed in to the function. * t * t is only one of the parameters to this function. * t, sz * Yes, the function specifies two parameters: t and sz. * t, sz, i * the parameters include only those variables whose values that the function expects to receive as input. They are specified in the header of the function. Considering the function below, which of the following statements correctly invokes, or calls, this function (i.e., causes it to run)? Assume we already have a turtle named alex. ```python def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) ``` * def drawSquare(t, sz) * No, t and sz are the names of the formal parameters to this function. When the function is called, it requires actual values to be passed in. * drawSquare * A function call always requires parentheses after the name of the function. * drawSquare(10) * This function takes two parameters (arguments) * drawSquare(alex, 10): * A colon is only required in a function definition. It will cause an error with a function call. * drawSquare(alex, 10) * Since alex was already previously defined and 10 is a value, we have passed in two correct values for this function. True or false: A function can be called several times by placing a function call in the body of a loop. * True * Yes, you can call a function multiple times by putting the call in a loop. * False * One of the purposes of a function is to allow you to call it more than once. Placing it in a loop allows it to executed multiple times as the body of the loop runs multiple times. ## 6.2. Functions that Return Values Most functions require arguments, values that control how the function does its job. For example, if you want to find the absolute value of a number, you have to indicate what the number is. Python has a built-in function for computing the absolute value: ```python print(abs(5)) print(abs(-5)) ``` In this example, the arguments to the `abs` function are 5 and -5. Some functions take more than one argument. For example the math module contains a function called `pow` which takes two arguments, the base and the exponent. ```python import math print(math.pow(2, 3)) print(math.pow(7, 4)) ``` Note Of course, we have already seen that raising a base to an exponent can be done with the \*\* operator. Another built-in function that takes more than one argument is `max`. ```python print(max(7, 11)) print(max(4, 1, 17, 2, 12)) print(max(3 * 11, 5 ** 3, 512 - 9, 1024 ** 0)) ``` `max` can be sent any number of arguments, separated by commas, and will return the maximum value sent. The arguments can be either simple values or expressions. In the last example, 503 is returned, since it is larger than 33, 125, and 1. Note that `max` also works on lists of values. Furthermore, functions like `range`, `int`, `abs` all return values that can be used to build more complex expressions. So an important difference between these functions and one like `drawSquare` is that `drawSquare` was not executed because we wanted it to compute a value — on the contrary, we wrote `drawSquare` because we wanted it to execute a sequence of steps that caused the turtle to draw a specific shape. Functions that return values are sometimes called **fruitful functions**. In many other languages, a chunk that doesn’t return a value is called a **procedure**, but we will stick here with the Python way of also calling it a function, or if we want to stress it, a *non-fruitful* function. Fruitful functions still allow the user to provide information (arguments). However there is now an additional piece of data that is returned from the function.  How do we write our own fruitful function? Let’s start by creating a very simple mathematical function that we will call `square`. The square function will take one number as a parameter and return the result of squaring that number. Here is the black-box diagram with the Python code following.  ```python def square(x): y = x * x return y toSquare = 10 result = square(toSquare) print("The result of", toSquare, "squared is", result) ``` The **return** statement is followed by an expression which is evaluated. Its result is returned to the caller as the “fruit” of calling this function. Because the return statement can contain any Python expression we could have avoided creating the **temporary variable** `y` and simply used `return x*x`. Try modifying the square function above to see that this works just the same. On the other hand, using **temporary variables** like `y` in the program above makes debugging easier. These temporary variables are examples of **local variables**, pursued further in the next section. Notice something important here. The name of the variable we pass as an argument — `toSquare` — has nothing to do with the name of the formal parameter — `x`. It is as if `x = toSquare` is executed when `square` is called. It doesn’t matter what the value was named in the caller. In `square`, it’s name is `x`. You can see this very clearly in codelens, where the **global variables** (variables defined outside of any function) and the local variables for the square function are in separate boxes. As you step through the example in codelens notice that the **return** statement not only causes the function to return a value, but it also returns the flow of control back to the place in the program where the function call was made. this is true in general: Note The call to a function *terminates* after the execution of a return statement. This is fairly obvious if the return statement is the last statement in the function, but we will see later where it makes sense to have a return statement even when other statements follow, and the further statements are *not* executed. Activity: CodeLens 6.2.5 (ch04\_clsquare) Another important thing to notice as you step through this codelens demonstration is the movement of the red and green arrows. Codelens uses these arrows to show you where it is currently executing. Recall that the red arrow always points to the next line of code that will be executed. The light green arrow points to the line that was just executed in the last step. When you first start running this codelens demonstration you will notice that there is only a red arrow and it points to line 1. This is because line 1 is the next line to be executed and since it is the first line, there is no previously executed line of code. When you click on the forward button, notice that the red arrow moves to line 5, skipping lines 2 and 3 of the function (and the light green arrow has now appeared on line 1). Why is this? The answer is that function definition is not the same as function execution. Lines 2 and 3 will not be executed until the function is called on line 6. Line 1 defines the function and the name `square` is added to the global variables, but that is all the `def` does at that point. The body of the function will be executed later. Continue to click the forward button to see how the flow of control moves from the call, back up to the body of the function, and then finally back to line 7, after the function has returned its value and the value has been assigned to `squareResult`. Finally, there is one more aspect of function return values that should be noted. All Python functions return the value `None` unless there is an explicit return statement with a value other than `None.` Consider the following common mistake made by beginning Python programmers. As you step through this example, pay very close attention to the return value in the local variables listing. Then look at what is printed when the function returns. Activity: CodeLens 6.2.6 (ch04\_clsquare\_bad) The problem with this function is that even though it prints the value of the square, that value will not be returned to the place where the call was made. Since line 6 uses the return value as the right hand side of an assignment statement, the evaluation of the function will be `None`. In this case, `squareResult` will refer to that value after the assignment statement and therefore the result printed in line 7 is incorrect. Typically, functions will return values that can be printed or processed in some other way by the caller. **Check your understanding** What is wrong with the following function definition: ```python def addEm(x, y, z): return x + y + z print('the answer is', x + y + z) ``` * You should never use a print statement in a function definition. * Although you should not mistake print for return, you may include print statements inside your functions. * You should not have any statements in a function after the return statement. Once the function gets to the return statement it will immediately stop executing the function. * This is a very common mistake so be sure to watch out for it when you write your code! * You must calculate the value of x+y+z before you return it. * Python will automatically calculate the value x+y+z and then return it in the statement as it is written * A function cannot return a number. * Functions can return any legal data, including (but not limited to) numbers, strings, turtles, etc. What will the following function return? ```python def addEm(x, y, z): print(x + y + z) ``` * None * We have accidentally used print where we mean return. Therefore, the function will return the value None by default. This is a VERY COMMON mistake so watch out! This mistake is also particularly difficult to find because when you run the function the output looks the same. It is not until you try to assign its value to a variable that you can notice a difference. * The value of x + y + z * Careful! This is a very common mistake. Here we have printed the value x+y+z but we have not returned it. To return a value we MUST use the return keyword. * The string 'x + y + z' * x+y+z calculates a number (assuming x+y+z are numbers) which represents the sum of the values x, y and z. ## 6.3. Unit Testing A **test case** expresses requirements for a program, in a way that can be checked automatically. Specifically, a test asserts something about the state of the program at a particular point in its execution. A **unit test** is an automatic procedure used to validate that individual units of code are working properly. A function is one form of a unit. A collection of these unit tests is called a **test suite**. We have previously suggested that it’s a good idea to first write down comments about what your code is supposed to do, before actually writing the code. It is an even better idea to write down some test cases before writing a program. There are several reasons why it’s a good habit to write test cases. * Before we write code, we have in mind what it *should* do, but those thoughts may be a little vague. Writing down test cases forces us to be more concrete about what should happen. * As we write the code, the test cases can provide automated feedback. You’ve actually been the beneficiary of such automated feedback via test cases throughout this book in some of the activecode windows and almost all of the exercises. We wrote the code for those test cases but kept it hidden, so as not to confuse you and also to avoid giving away the answers. You can get some of the same benefit from writing your own test cases. * In larger software projects, the set of test cases can be run every time a change is made to the code base. **Unit tests** check that small bits of code are correctly implemented. One way to implement unit tests in Python is with `assert`. * Following the word assert there will be a python expression. * If that expression evaluates to the Boolean `False`, then the interpreter will raise a runtime error. * If the expression evaluates to `True`, then nothing happens and the execution goes on to the next line of code. Take a look at the way assert is used in the following code. ```python assert type(9//5) == int assert type(9.0//5) == int ``` In the code above, we explicitly state some natural assumptions about how truncated division might work in python. It turns out that the second asumption is wrong: `9.0//5` produces `2.0`, a floating point value! The python interpreter does not enforce restrictions about the data types of objects that can be bound to particular variables; however, type checking could alert us that something has gone wrong in our program execution. If we are assuming at that `x` is a list, but it’s actually an integer, then at some point later in the program execution, there will probably be an error. We can add `assert` statements that will cause an error to be flagged sooner rather than later, which might make it a lot easier to debug. **Check your understanding** When `assert x==y` is executed and x and y have the same values, what will happen? * A runtime error will occur * The expression ``x==y`` evaluates to ``True`` * A message is printed out saying that the test failed. * The expression ``x==y`` evaluates to ``True`` * x will get the value that y currently has * ``x==y`` is a Boolean expression, not an assignment statement * Nothing will happen * The expression ``x==y`` evaluates to ``True`` * A message is printed out saying that the test passed. * When an assertion test passes, no message is printed. ### 6.3.1. `assert` with `for` loops Why would you ever want to write a line of code that can never compute anything useful for you, but sometimes causes a runtime error? For all the reasons we described above about the value of automated tests. You want a test that will alert that you that some condition you assumed was true is not in fact true. It’s much better to be alerted to that fact right away than to have some unexpected result much later in your program execution, which you will have trouble tracing to the place where you had an error in your code. Why doesn’t `assert` print out something saying that the test passed? The reason is that you don’t want to clutter up your output window with the results of automated tests that pass. You just want to know when one of your tests fails. In larger projects, other testing harnesses are used instead of `assert`, such as the python `unittest` module. Those provide some output summarizing tests that have passed as well as those that failed. In this textbook, we will just use simple `assert` statements for automated tests. In the code below, `lst` is bound to a list object. In python, not all the elements of a list have to be of the same type. We can check that they all have the same type and get an error if they are not. Notice that with `lst2`, one of the assertions fails. ```python lst = ['a', 'b', 'c'] first_type = type(lst[0]) for item in lst: assert type(item) == first_type lst2 = ['a', 'b', 'c', 17] first_type = type(lst2[0]) for item in lst2: assert type(item) == first_type ``` ### 6.3.2. Return Value Tests Testing whether a function returns the correct value is the easiest test case to define. You simply check whether the result of invoking the function on a particular input produces the particular output that you expect. Take a look at the following code. ```python def square(x): #raise x to the second power return x*x print('testing square function') assert square(3) == 9 ``` Because each test checks whether a function works properly on specific inputs, the test cases will never be complete: in principle, a function might work properly on all the inputs that are tested in the test cases, but still not work properly on some other inputs. That’s where the art of defining test cases comes in: you try to find specific inputs that are representative of all the important kinds of inputs that might ever be passed to the function. For the hangman game, this ‘blanked’ function takes a word and some letters that have been guessed, and returns a version of the word with \_ for all the letters that haven’t been guessed. Which of the following is the correct way to write a test to check that ‘under’ will be blanked as `'u_d__'` when the user has guessed letters d and u so far? * assert blanked('under', 'du', 'u\_d\_\_') == True * blanked only takes two inputs; this provides three inputs to the blanked function * assert blanked('under', 'u\_d\_\_') == 'du' * The second argument to the blanked function should be the letters that have been guessed, not the blanked version of the word * assert blanked('under', 'du') == 'u\_d\_\_' * This checks whether the value returned from the blanked function is 'u\_d\_\_'. ## 6.4. Variables and Parameters are Local An assignment statement in a function creates a **local variable** for the variable on the left hand side of the assignment operator. It is called local because this variable only exists inside the function and you cannot use it outside. For example, consider again the `square` function: Activity: CodeLens 6.4.1 (bad\_local) If you press the ‘last >>’ button you will see an error message. When we try to use `y` on line 6 (outside the function) Python looks for a global variable named `y` but does not find one. This results in the error: `Name Error: 'y' is not defined.` The variable `y` only exists while the function is being executed — we call this its **lifetime**. When the execution of the function terminates (returns), the local variables are destroyed. Codelens helps you visualize this because the local variables disappear after the function returns. Go back and step through the statements paying particular attention to the variables that are created when the function is called. Note when they are subsequently destroyed as the function returns. Formal parameters are also local and act like local variables. For example, the lifetime of `x` begins when `square` is called, and its lifetime ends when the function completes its execution. So it is not possible for a function to set some local variable to a value, complete its execution, and then when it is called again next time, recover the local variable. Each call of the function creates new local variables, and their lifetimes expire when the function returns to the caller. On the other hand, it is legal for a function to access a global variable. However, this is considered **bad form** by nearly all programmers and should be avoided. Look at the following, nonsensical variation of the square function. ```python def badsquare(x): y = x ** power return y power = 2 result = badsquare(10) print(result) ``` Although the `badsquare` function works, it is silly and poorly written. We have done it here to illustrate an important rule about how variables are looked up in Python. First, Python looks at the variables that are defined as local variables in the function. We call this the **local scope**. If the variable name is not found in the local scope, then Python looks at the global variables, or **global scope**. This is exactly the case illustrated in the code above. `power` is not found locally in `badsquare` but it does exist globally. The appropriate way to write this function would be to pass power as a parameter. For practice, you should rewrite the badsquare example to have a second parameter called power. There is another variation on this theme of local versus global variables. Assignment statements in the local function cannot change variables defined outside the function, without further (discouraged) special syntax. Consider the following codelens example: Activity: CodeLens 6.4.3 (cl\_powerof\_bad) Now step through the code. What do you notice about the values of variable `power` in the local scope compared to the variable `power` in the global scope? The value of `power` in the local scope was different than the global scope. That is because in this example `power` was used on the left hand side of the assignment statement `power = p`. When a variable name is used on the left hand side of an assignment statement Python creates a local variable. When a local variable has the same name as a global variable we say that the local shadows the global. A **shadow** means that the global variable cannot be accessed by Python because the local variable will be found first. This is another good reason not to use global variables. As you can see, it makes your code confusing and difficult to understand. To cement all of these ideas even further lets look at one final example. Inside the `square` function we are going to make an assignment to the parameter `x` There’s no good reason to do this other than to emphasize the fact that the parameter `x` is a local variable. If you step through the example in codelens you will see that although `x` is 0 in the local variables for `square`, the `x` in the global scope remains 2. This is confusing to many beginning programmers who think that an assignment to a formal parameter will cause a change to the value of the variable that was used as the actual parameter, especially when the two share the same name. But this example demonstrates that that is clearly not how Python operates. Activity: CodeLens 6.4.4 (cl\_change\_parm) **Check your understanding** What is a variable’s scope? * Its value * Value is the contents of the variable. Scope concerns where the variable is "known". * The range of statements in the code where a variable can be accessed. * The range in which a variable can be accessed is it's scope. For example if a variable is defined in a function, then the scope of the variable is that function. * Its name * The name of a variable is just an identifier or alias. Scope concerns where the variable is "known". What is a local variable? * A temporary variable that is only used inside a function * Yes, a local variable is a temporary variable that is only known (only exists) in the function it is defined in. * The same as a parameter * While parameters may be considered local variables, functions may also define and use additional local variables. * Another name for any variable * Variables that are used outside a function are not local, but rather global variables. Can you use the same name for a local variable as a global variable? * Yes, and there is no reason not to. * While there is no problem as far as Python is concerned, it is generally considered bad style because of the potential for the programmer to get confused. * Yes, but it is considered bad form. * it is generally considered bad style because of the potential for the programmer to get confused. If you must use global variables (also generally bad form) make sure they have unique names. * No, it will cause an error. * Python manages global and local scope separately and has clear rules for how to handle variables with the same name in different scopes, so this will not cause a Python error. ## 6.5. The Accumulator Pattern In the previous example, we wrote a function that computes the square of a number. The algorithm we used in the function was simple: multiply the number by itself. In this section we will reimplement the square function and use a different algorithm, one that relies on addition instead of multiplication. If you want to multiply two numbers together, the most basic approach is to think of it as repeating the process of adding one number to itself. The number of repetitions is where the second number comes into play. For example, if we wanted to multiply three and five, we could think about it as adding three to itself five times. Three plus three is six, plus three is nine, plus three is 12, and finally plus three is 15. Generalizing this, if we want to implement the idea of squaring a number, call it n, we would add n to itself n times. Do this by hand first and try to isolate exactly what steps you take. You’ll find you need to keep some “running total” of the sum so far, either on a piece of paper, or in your head. Remembering things from one step to the next is precisely why we have variables in a program. This means that we will need some variable to remember the “running total”. It should be initialized with a value of zero. Then, we need to **update** the “running total” the correct number of times. For each repetition, we’ll want to update the running total by adding the number to it. In words we could say it this way. To square the value of n, we will repeat the process of updating a running total n times. To update the running total, we take the old value of the “running total” and add n. That sum becomes the new value of the “running total”. Here is the program in activecode. Note that the heading of the function definition is the same as it was before. All that has changed is the details of how the squaring is done. This is a great example of “black box” design. We can change out the details inside of the box and still use the function exactly as we did before. ```python def square(x): runningtotal = 0 for counter in range(x): runningtotal = runningtotal + x return runningtotal toSquare = 10 squareResult = square(toSquare) print("The result of", toSquare, "squared is", squareResult) ``` In the program above, notice that the variable `runningtotal` starts out with a value of 0. Next, the iteration is performed `x` times. Inside the for loop, the update occurs. `runningtotal` is reassigned a new value which is the old value plus the value of `x`. This pattern of iterating the updating of a variable is commonly referred to as the **accumulator pattern**. We refer to the variable as the **accumulator**. This pattern will come up over and over again. Remember that the key to making it work successfully is to be sure to initialize the variable before you start the iteration. Once inside the iteration, it is required that you update the accumulator. Note What would happen if we put the assignment `runningTotal = 0` inside the for statement? Not sure? Try it and find out. Here is the same program in codelens. Step through the function and watch the “running total” accumulate the result. Activity: CodeLens 6.5.3 (sq\_accum3) ### 6.5.1. The General Accumulator Pattern ```python initialize the accumulator variable repeat: modify the accumulator variable # when the loop terminates the accumulator has the correct value ``` Note This workspace is provided for your convenience. You can use this activecode window to try out anything you like. **Check your understanding** Consider the following code: ```python def square(x): for counter in range(x): runningtotal = 0 runningtotal = runningtotal + x return runningtotal ``` What happens if you put the initialization of runningtotal (the line runningtotal = 0) inside the for loop as the first instruction in the loop? * The square function will return x instead of x \* x * The variable runningtotal will be reset to 0 each time through the loop. However because this assignment happens as the first instruction, the next instruction in the loop will set it back to x. When the loop finishes, it will have the value x, which is what is returned. * The square function will cause an error * Assignment statements are perfectly legal inside loops and will not cause an error. * The square function will work as expected and return x \* x * By putting the statement that sets runningtotal to 0 inside the loop, that statement gets executed every time through the loop, instead of once before the loop begins. The result is that runningtotal is 'cleared' (reset to 0) each time through the loop. * The square function will return 0 instead of x \* x * The line runningtotal = 0 is the first line in the for loop, but immediately after this line, the line runningtotal = runningtotal + x will execute, giving runningtotal a non-zero value (assuming x is non-zero). Rearrange the code statements so that the program will add up the first n odd numbers where n is provided by the user. ```python n = int(input('How many odd numbers would you like to add together?')) thesum = 0 oddnumber = 1 --- for counter in range(n): --- thesum = thesum + oddnumber oddnumber = oddnumber + 2 --- print(thesum) ``` ### 6.5.2. A Variation on the Accumulator Pattern ```python def square(x): '''raise x to the second power''' runningtotal = 0 for counter in range(x): runningtotal = runningtotal + x return runningtotal toSquare = 10 squareResult = square(toSquare) print("The result of", toSquare, "squared is", squareResult) ``` Modify the program … Change the value of `toSquare` in line 9 to `-10` and run. We now see that our function has a semantic error. Remember when we first introduced the square function, unit testing and equivalence classes? Change the value of `toSquare` in line 9 back to `10` and run. What would happen if we change `runningtotal = runningtotal + x` to use **multiplication** instead of addition? Make this change to the program and look at the output. It is very important to properly initialize the accumulator variable. Do a web search on `additive identity` and `multiplicative identity`. **Properly initialize the accumulator variable** and run the program. Now we get an answer other than 0. However, the answer is not the square of of `x`. It is also important that the loop repeat the proper number of times. How many times do we need to execute line 5 to get the square of `x`? **Change line 4 to repeat the correct number of times**. Now the program should produce the correct result. Change the value of `toSquare` in line 9 to `-10` and run. Now negative inputs also work! Remember that the boundary between our equivalence classes is 0. Try that value for `toSquare` also. ## 6.6. Functions can Call Other Functions It is important to understand that each of the functions we write can be used and called from other functions we write. This is one of the most important ways that computer scientists take a large problem and break it down into a group of smaller problems. This process of breaking a problem into smaller subproblems is called **functional decomposition**. Here’s a simple example of functional decomposition using two functions. The first function called `square` simply computes the square of a given number. The second function called `sum_of_squares` makes use of square to compute the sum of three numbers that have been squared. Activity: CodeLens 6.6.1 (sumofsquares) Even though this is a pretty simple idea, in practice this example illustrates many very important Python concepts, including local and global variables along with parameter passing. Note that when you step through this example, codelens bolds line 1 and line 5 as the functions are defined. The body of square is not executed until it is called from the `sum_of_squares` function for the first time on line 6. Also notice that when `square` is called there are two groups of local variables, one for `square` and one for `sum_of_squares`. As you step through you will notice that `x`, and `y` are local variables in both functions and may even have different values. This illustrates that even though they are named the same, they are in fact, very different. Now we will look at another example that uses two functions. This example illustrates an important computer science problem solving technique called **generalization**. Assume we want to write a function to draw a square. The generalization step is to realize that a square is just a special kind of rectangle. To draw a rectangle we need to be able to call a function with different arguments for width and height. Unlike the case of the square, we cannot repeat the same thing 4 times, because the four sides are not equal. However, it is the case that drawing the bottom and right sides are the same sequence as drawing the top and left sides. So we eventually come up with this rather nice code that can draw a rectangle. ```python def drawRectangle(t, w, h): """Get turtle t to draw a rectangle of width w and height h.""" for i in range(2): t.forward(w) t.left(90) t.forward(h) t.left(90) ``` The parameter names are chosen as single letters for conciseness. In real programs, we will insist on better variable names than this. The point is that the program doesn’t “understand” that you’re drawing a rectangle or that the parameters represent the width and the height. Concepts like rectangle, width, and height are meaningful for humans. They are not concepts that the program or the computer understands. *Thinking like a computer scientist* involves looking for patterns and relationships. In the code above, we’ve done that to some extent. We did not just draw four sides. Instead, we spotted that we could draw the rectangle as two halves and used a loop to repeat that pattern twice. But now we might spot that a square is a special kind of rectangle. A square simply uses the same value for both the height and the width. We already have a function that draws a rectangle, so we can use that to draw our square. ```python def drawSquare(tx, sz): # a new version of drawSquare drawRectangle(tx, sz, sz) ``` Here is the entire example with the necessary set up code. ```python import turtle def drawRectangle(t, w, h): """Get turtle t to draw a rectangle of width w and height h.""" for i in range(2): t.forward(w) t.left(90) t.forward(h) t.left(90) def drawSquare(tx, sz): # a new version of drawSquare drawRectangle(tx, sz, sz) wn = turtle.Screen() # Set up the window wn.bgcolor("lightgreen") tess = turtle.Turtle() # create tess drawSquare(tess, 50) wn.exitonclick() ``` There are some points worth noting here: * Functions can call other functions. * Rewriting `drawSquare` like this captures the relationship that we’ve spotted. * A caller of this function might say `drawSquare(tess, 50)`. The parameters of this function, `tx` and `sz`, are assigned the values of the tess object, and the integer 50 respectively. * In the body of the function, `tz` and `sz` are just like any other variable. * When the call is made to `drawRectangle`, the values in variables `tx` and `sz` are fetched first, then the call happens. So as we enter the top of function `drawRectangle`, its variable `t` is assigned the tess object, and `w` and `h` in that function are both given the value 50. So far, it may not be clear why it is worth the trouble to create all of these new functions. Actually, there are a lot of reasons, but this example demonstrates two: 1. Creating a new function gives you an opportunity to name a group of statements. Functions can simplify a program by hiding a complex computation behind a single command. The function (including its name) can capture your mental chunking, or *abstraction*, of the problem. 2. Creating a new function can make a program smaller by eliminating repetitive code. 3. Sometimes you can write functions that allow you to solve a specific problem using a more general solution. Lab * [Drawing a Circle](../Labs/lab04_01.html) In this guided lab exercise we will work through a simple problem solving exercise related to drawing a circle with the turtle. ## 6.7. Flow of Execution Summary When you are working with functions it is really important to know the order in which statements are executed. This is called the **flow of execution** and we’ve already talked about it a number of times in this chapter. Execution always begins at the first statement of the program. Statements are executed one at a time, in order, from top to bottom. Function definitions do not alter the flow of execution of the program, but remember that statements inside the function are not executed until the function is called. Function calls are like a detour in the flow of execution. Instead of going to the next statement, the flow jumps to the first line of the called function, executes all the statements there, and then comes back to pick up where it left off. That sounds simple enough, until you remember that one function can call another. While in the middle of one function, the program might have to execute the statements in another function. But while executing that new function, the program might have to execute yet another function! Fortunately, Python is adept at keeping track of where it is, so each time a function completes, the program picks up where it left off in the function that called it. When it gets to the end of the program, it terminates. What’s the moral of this sordid tale? When you read a program, don’t read from top to bottom. Instead, follow the flow of execution. This means that you will read the `def` statements as you are scanning from top to bottom, but you should skip the body of the function until you reach a point where that function is called. **Check your understanding** Consider the following Python code. Note that line numbers are included on the left. ```python 1def pow(b, p): 2 y = b ** p 3 return y 4 5def square(x): 6 a = pow(x, 2) 7 return a 8 9n = 5 10result = square(n) 11print(result) ``` Which of the following best reflects the order in which these lines of code are processed in Python? * 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 * Although Python typically processes lines in order from top to bottom, function definitions and calls are an exception to this rule. * 1, 2, 3, 5, 6, 7, 9, 10, 11 * Although Python typically processes lines in order from top to bottom, function definitions and calls are an exception to this rule. Although this order skips blank lines, it still lists the lines of code in order. * 9, 10, 11, 1, 2, 3, 5, 6, 7 * This is close, in that Python will not execute the functions until after they are called, but there are two problems here. First, Python does not know which lines are function definitions until it processes them, so it must at least process the function headers before skipping over the functions. Section, notice that line 10 involves a function call. Python must execute the function square before moving on to line 11. * 9, 10, 5, 6, 1, 2, 3, 6, 7, 10, 11 * This is close, in that Python will not execute the functions until after they are called, but there is one problem here. Python does not know which lines are function definitions until it processes them, so it must at least process the function headers before skipping over the functions. * 1, 5, 9, 10, 5, 6, 1, 2, 3, 6, 7, 10, 11 * Python starts at line 1, notices that it is a function definition and skips over all of the lines in the function definition until it finds a line that it no longer included in the function (line 5). It then notices line 5 is also a function definition and again skips over the function body to line 9. On line 10 it notices it has a function to execute, so it goes back and executes that function. Notice that that function includes another function call. It returns from the function call and completes the assignment in line 6. Then it returns the result of line 7 and completes the assignment in line 10. Finally, it will go to line 11 after the function square and the assignment are complete. Consider the following Python code. Note that line numbers are included on the left. ```python 1def pow(b, p): 2 y = b ** p 3 return y 4 5def square(x): 6 a = pow(x, 2) 7 return a 8 9n = 5 10result = square(n) 11print(result) ``` What does this function print? * 25 * The function square returns the square of its input (via a call to pow) * 5 * What is printed is the output of the square function. 5 is the input to the square function. * 125 * Notice that pow is called from within square with a base (b) of 5 and a power (p) of two. * 32 * Notice that pow is called from within square with a base (b) of 5 and a power (p) of two. ## 6.8. Using a Main Function Using functions is a good idea. It helps us to modularize our code by breaking a program into logical parts where each part is responsible for a specific task. For example, in one of our first programs there was a function called `drawSquare` that was responsible for having some turtle draw a square of some size. The actual turtle and the actual size of the square were defined to be provided as parameters. Here is that original program. ```python import turtle def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") alex = turtle.Turtle() # create alex drawSquare(alex, 50) # Call the function to draw the square wn.exitonclick() ``` If you look closely at the structure of this program, you will notice that we first perform all of our necessary `import` statements, in this case to be able to use the `turtle` module. Next, we define the function `drawSquare`. At this point, we could have defined as many functions as were needed. Finally, there are five statements that set up the window, create the turtle, perform the function invocation, and wait for a user click to terminate the program. These final five statements perform the main processing that the program will do. Notice that much of the detail has been pushed inside the `drawSquare` function. However, there are still these five lines of code that are needed to get things done. In many programming languages (e.g. Java and C++), it is not possible to simply have statements sitting alone like this at the bottom of the program. They are required to be part of a special function that is automatically invoked by the operating system when the program is executed. This special function is called **main**. Although this is not required by the Python programming language, it is actually a good idea that we can incorporate into the logical structure of our program. In other words, these five lines are logically related to one another in that they provide the main tasks that the program will perform. Since functions are designed to allow us to break up a program into logical pieces, it makes sense to call this piece `main`. The following activecode shows this idea. In line 11 we have defined a new function called `main` that doesn’t need any parameters. The five lines of main processing are now placed inside this function. Finally, in order to execute that main processing code, we need to invoke the `main` function (line 20). When you push run, you will see that the program works the same as it did before. ```python import turtle def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) def main(): # Define the main function wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") alex = turtle.Turtle() # create alex drawSquare(alex, 50) # Call the function to draw the square wn.exitonclick() main() # Invoke the main function ``` Now our program structure is as follows. First, import any modules that will be required. Second, define any functions that will be needed. Third, define a `main` function that will get the process started. And finally, invoke the main function (which will in turn call the other functions as needed). Note In Python there is nothing special about the name `main`. We could have called this function anything we wanted. We chose `main` just to be consistent with some of the other languages. **Advanced Topic** Before the Python interpreter executes your program, it defines a few special variables. One of those variables is called `__name__` and it is automatically set to the string value `"__main__"` when the program is being executed by itself in a standalone fashion. On the other hand, if the program is being imported by another program, then the `__name__` variable is set to the name of that module. This means that we can know whether the program is being run by itself or whether it is being used by another program and based on that observation, we may or may not choose to execute some of the code that we have written. For example, assume that we have written a collection of functions to do some simple math. We can include a `main` function to invoke these math functions. It is much more likely, however, that these functions will be imported by another program for some other purpose. In that case, we would not want to execute our main function. The activecode below defines two simple functions and a main. ```python def squareit(n): return n * n def cubeit(n): return n*n*n def main(): anum = int(input("Please enter a number")) print(squareit(anum)) print(cubeit(anum)) if __name__ == "__main__": main() ``` Line 12 uses an `if` statement to ask about the value of the `__name__` variable. If the value is `"__main__"`, then the `main` function will be called. Otherwise, it can be assumed that the program is being imported into another program and we do not want to call `main` because that program will invoke the functions as needed. This ability to conditionally execute our main function can be extremely useful when we are writing code that will potentially be used by others. It allows us to include functionality that the user of the code will not need, most often as part of a testing process to be sure that the functions are working correctly. Note In order to conditionally execute the `main` function, we used a structure called an `if` statement to create what is known as selection. This topic will be studied in much more detail later. ## 6.9. Program Development At this point, you should be able to look at complete functions and tell what they do. Also, if you have been doing the exercises, you have written some small functions. As you write larger functions, you might start to have more difficulty, especially with runtime and semantic errors. To deal with increasingly complex programs, we are going to suggest a technique called **incremental development**. The goal of incremental development is to avoid long debugging sessions by adding and testing only a small amount of code at a time. As an example, suppose you want to find the distance between two points, given by the coordinates (x1, y1) and (x2, y2). By the Pythagorean theorem, the distance is:  The first step is to consider what a `distance` function should look like in Python. In other words, what are the inputs (parameters) and what is the output (return value)? In this case, the two points are the inputs, which we can represent using four parameters. The return value is the distance, which is a floating-point value. Already we can write an outline of the function that captures our thinking so far. ```python def distance(x1, y1, x2, y2): return 0.0 ``` Obviously, this version of the function doesn’t compute distances; it always returns zero. But it is syntactically correct, and it will run, which means that we can test it before we make it more complicated. We import the test module to enable us to write a unit test for the function. ```python import test def distance(x1, y1, x2, y2): return 0.0 test.testEqual(distance(1, 2, 1, 2), 0) ``` The `testEqual` function from the test module calls the distance function with sample inputs: (1,2, 1,2). The first 1,2 are the coordinates of the first point and the second 1,2 are the coordinates of the second point. What is the distance between these two points? Zero. `testEqual` compares what is returned by the distance function and the 0 (the correct answer). Extend the program … On line 6, write another unit test. Use (1,2, 4,6) as the parameters to the distance function. How far apart are these two points? Use that value (instead of 0) as the correct answer for this unit test. On line 7, write another unit test. Use (0,0, 1,1) as the parameters to the distance function. How far apart are these two points? Use that value as the correct answer for this unit test. The first test passes but the others fail since the distance function does not yet contain all the necessary steps. **When testing a function, it is essential to know the right answer.** For the second test the horizontal distance equals 3 and the vertical distance equals 4; that way, the result is 5 (the hypotenuse of a 3-4-5 triangle). For the third test, we have a 1-1-sqrt(2) triangle. At this point we have confirmed that the function is syntactically correct, and we can start adding lines of code. After each incremental change, we test the function again. If an error occurs at any point, we know where it must be — in the last line we added. A logical first step in the computation is to find the differences x2- x1 and y2- y1. We will store those values in temporary variables named `dx` and `dy`. ```python def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 return 0.0 ``` Next we compute the sum of squares of `dx` and `dy`. ```python def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dsquared = dx**2 + dy**2 return 0.0 ``` Again, we could run the program at this stage and check the value of `dsquared` (which should be 25). Finally, using the fractional exponent `0.5` to find the square root, we compute and return the result. ```python import test def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dsquared = dx**2 + dy**2 result = dsquared**0.5 return result test.testEqual(distance(1,2, 1,2), 0) test.testEqual(distance(1,2, 4,6), 5) test.testEqual(distance(0,0, 1,1), 1.41) ``` Fix the error … Two of the tests pass but the last one fails. Is there still an error in the function? Frequently we discover errors in the functions that we are writing. However, it is possible that there is an error in a test. Here the error is in the precision of the correct answer. The third test fails because by default testEqual checks 5 digits to the right of the decimal point. * Change `1.41` to `1.41421` and run. The test will pass. There are circumstances where 2 digits to the right of the decimal point is sufficiently precise. * Copy line 11 on to line 12. On line 12, change `1.41421` to `1.41`. Run. The test fails. * Type `, 2` after 1.41. (The 2 represents the precision of the test – how many digits to the right of the decimal that must be correct.) Run. Now all four the tests pass! Wonderful! However, you may still need to perform additional tests. When you start out, you might add only a line or two of code at a time. As you gain more experience, you might find yourself writing and debugging bigger conceptual chunks. As you improve your programming skills you should find yourself managing bigger and bigger chunks: this is very similar to the way we learned to read letters, syllables, words, phrases, sentences, paragraphs, etc., or the way we learn to chunk music — from indvidual notes to chords, bars, phrases, and so on. The key aspects of the process are: 1. Make sure you know what you are trying to accomplish. Then you can write appropriate unit tests. 2. Start with a working skeleton program and make small incremental changes. At any point, if there is an error, you will know exactly where it is. 3. Use temporary variables to hold intermediate values so that you can easily inspect and check them. 4. Once the program is working, you might want to consolidate multiple statements into compound expressions, but only do this if it does not make the program more difficult to read. ## 6.10. Composition As we have already seen, you can call one function from within another. This ability to build functions by using other functions is called **composition**. As an example, we’ll write a function that takes two points, the center of the circle and a point on the perimeter, and computes the area of the circle. Assume that the center point is stored in the variables `xc` and `yc`, and the perimeter point is in `xp` and `yp`. The first step is to find the radius of the circle, which is the distance between the two points. Fortunately, we’ve just written a function, `distance`, that does just that, so now all we have to do is use it: ```python radius = distance(xc, yc, xp, yp) ``` The second step is to find the area of a circle with that radius and return it. Again we will use one of our earlier functions: ```python result = area(radius) return result ``` Wrapping that up in a function, we get: ```python def distance(x1, y1, x2, y2): dx = x2 - x1 dy = y2 - y1 dsquared = dx**2 + dy**2 result = dsquared**0.5 return result def area(radius): b = 3.14159 * radius**2 return b def area2(xc, yc, xp, yp): radius = distance(xc, yc, xp, yp) result = area(radius) return result print(area2(0,0,1,1)) ``` We called this function `area2` to distinguish it from the `area` function defined earlier. There can only be one function with a given name within a module. Note that we could have written the composition without storing the intermediate results. ```python def area2(xc, yc, xp, yp): return area(distance(xc, yc, xp, yp)) ``` ## 6.11. A Turtle Bar Chart Recall from our discussion of modules that there were a number of things that turtles can do. Here are a couple more tricks (remember that they are all described in the module documentation). * We can get a turtle to display text on the canvas at the turtle’s current position. The method is called `write`. For example, `alex.write("Hello")` would write the string hello at the current position. * One can fill a shape (circle, semicircle, triangle, etc.) with a fill color. It is a two-step process. First you call the method `begin_fill`, for example `alex.begin_fill()`. Then you draw the shape. Finally, you call `end_fill` ( `alex.end_fill()`). * We’ve previously set the color of our turtle - we can now also set it’s fill color, which need not be the same as the turtle and the pen color. To do this, we use a method called `fillcolor`, for example, `alex.fillcolor("red")`. Ok, so can we get tess to draw a bar chart? Let us start with some data to be charted, `xs = [48, 117, 200, 240, 160, 260, 220]` Corresponding to each data measurement, we’ll draw a simple rectangle of that height, with a fixed width. Here is a simplified version of what we would like to create.  We can quickly see that drawing a bar will be similar to drawing a rectangle or a square. Since we will need to do it a number of times, it makes sense to create a function, `drawBar`, that will need a turtle and the height of the bar. We will assume that the width of the bar will be 40 units. Once we have the function, we can use a basic for loop to process the list of data values. ```python def drawBar(t, height): """ Get turtle t to draw one bar, of height. """ t.left(90) # Point up t.forward(height) # Draw up the left side t.right(90) t.forward(40) # width of bar, along the top t.right(90) t.forward(height) # And down again! t.left(90) # put the turtle facing the way we found it. ... for v in xs: # assume xs and tess are ready drawBar(tess, v) ``` It is a nice start! The important thing here was the mental chunking. To solve the problem we first broke it into smaller pieces. In particular, our chunk is to draw one bar. We then implemented that chunk with a function. Then, for the whole chart, we repeatedly called our function. Next, at the top of each bar, we’ll print the value of the data. We will do this in the body of `drawBar` by adding `t.write(str(height))` as the new fourth line of the body. Note that we had to turn the number into a string. Finally, we’ll add the two methods needed to fill each bar. The one remaining problem is related the fact that our turtle lives in a world where position (0,0) is at the center of the drawing canvas. In this problem, it would help if (0,0) were in the lower left hand corner. To solve this we can use our `setworldcoordinates` method to rescale the window. While we are at it, we should make the window fit the data. The tallest bar will correspond to the maximum data value. The width of the window will need to be proportional to the number of bars (the number of data values) where each has a width of 40. Using this information, we can compute the coordinate system that makes sense for the data set. To make it look nice, we’ll add a 10 unit border around the bars. Here is the complete program. Try it and then change the data to see that it can adapt to the new values. Note also that we have stored the data values in a list and used a few list functions. We will have much more to say about lists in a later chapter. ```python import turtle def drawBar(t, height): """ Get turtle t to draw one bar, of height. """ t.begin_fill() # start filling this shape t.left(90) t.forward(height) t.write(str(height)) t.right(90) t.forward(40) t.right(90) t.forward(height) t.left(90) t.end_fill() # stop filling this shape xs = [48, 117, 200, 240, 160, 260, 220] # here is the data maxheight = max(xs) numbars = len(xs) border = 10 wn = turtle.Screen() # Set up the window and its attributes wn.setworldcoordinates(0-border, 0-border, 40*numbars+border, maxheight+border) wn.bgcolor("lightgreen") tess = turtle.Turtle() # create tess and set some attributes tess.color("blue") tess.fillcolor("red") tess.pensize(3) for a in xs: drawBar(tess, a) wn.exitonclick() ``` This code is quite concise, but each height label is partly covered by the top segment of its bar. Can you modifiy the `drawBar` code, moving the label up slightly but not changing the bar? Hint: The label cannot be drawn during the polygon fill sequence. Note This workspace is provided for your convenience. You can use this activecode window to try out anything you like. ## 6.12. Glossary chatterbox function : A function which interacts with the user (using `input` or `print`) when it should not. Silent functions that just convert their input arguments into their output results are usually the most useful ones. composition (of functions) : Calling one function from within the body of another, or using the return value of one function as an argument to the call of another. dead code : Part of a program that can never be executed, often because it appears after a `return` statement. fruitful function : A function that yields a return value instead of `None`. incremental development : A program development plan intended to simplify debugging by adding and testing only a small amount of code at a time. None : A special Python value. One use in Python is that it is returned by functions that do not execute a return statement with a return argument. return value : The value provided as the result of a function call. scaffolding : Code that is used during program development to assist with development and debugging. The unit test code that we added in this chapter are examples of scaffolding. temporary variable : A variable used to store an intermediate value in a complex calculation. ## 6.13. Exercises 1. Use the drawsquare function we wrote in this chapter in a program to draw the image shown below. Assume each side is 20 units. (Hint: notice that the turtle has already moved away from the ending point of the last square when the program ends.)  ```python import turtle def drawSquare(t, sz): """Get turtle t to draw a square of sz side""" for i in range(4): t.forward(sz) t.left(90) wn = turtle.Screen() wn.bgcolor("lightgreen") alex = turtle.Turtle() alex.color("pink") drawSquare(alex,20) wn.exitonclick() ``` ```python import turtle def drawSquare(t, sz): """Make turtle t draw a square of with side sz.""" for i in range(4): t.forward(sz) t.left(90) wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") alex = turtle.Turtle() # create alex alex.color('hotpink') alex.pensize(3) for i in range(5): drawSquare(alex, 20) # Call the function to draw the square alex.penup() alex.forward(40) # move alex to the starting position for the next square alex.pendown() wn.exitonclick() ``` [Show Comments](#disqus_thread) 2. Write a program to draw this. Assume the innermost square is 20 units per side, and each successive square is 20 units bigger, per side, than the one inside it.  3. Write a non-fruitful function `drawPoly(someturtle, somesides, somesize)` which makes a turtle draw a regular polygon. When called with `drawPoly(tess, 8, 50)`, it will draw a shape like this:  ```python import turtle def drawPoly(t, num_sides, side_length): for i in range(num_sides): t.forward(side_length) t.left(360/num_sides) wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") tess = turtle.Turtle() tess.color('hotpink') tess.pensize(3) drawPoly(tess, 8, 50) ``` [Show Comments](#disqus_thread) 4. Draw this pretty pattern.  5. The two spirals in this picture differ only by the turn angle. Draw both. [](../_images/tess_spirals.png) ```python import turtle def drawSpiral(t, angle): ''' takes a turtle, t, and an angle in degrees ''' length = 1 for i in range(84): t.forward(length) t.right(angle) length = length + 2 wn = turtle.Screen() # Set up the window and its attributes wn.bgcolor("lightgreen") guido = turtle.Turtle() # create guido guido.color('blue') ## draw the first spiral ## # position guido guido.penup() guido.backward(110) guido.pendown() # draw the spiral using a 90 degree turn angle drawSpiral(guido, 90) ## draw the second spiral ## # position guido guido.home() guido.penup() guido.forward(90) guido.pendown() drawSpiral(guido, 89) ``` [Show Comments](#disqus_thread) 6. Write a non-fruitful function `drawEquitriangle(someturtle, somesize)` which calls `drawPoly` from the previous question to have its turtle draw a equilateral triangle. 7. Write a fruitful function `sumTo(n)` that returns the sum of all integer numbers up to and including n. So `sumTo(10)` would be `1+2+3...+10` which would return the value 55. Use the equation (n \* (n + 1)) / 2. ```python def sumTo(n): # your code here ===== from unittest.gui import TestCaseGui class myTests(TestCaseGui): def testOne(self): self.assertAlmostEqual(sumTo(15),120.0,0,"Tested sumTo on input 15") self.assertAlmostEqual(sumTo(0),0.0,0,"Tested sumTo on input 0") self.assertAlmostEqual(sumTo(25),325.0,0,"Tested sumTo on input 25") self.assertAlmostEqual(sumTo(7),28.0,0,"Tested sumTo on input 7") myTests().main() ``` ```python from test import testEqual def sumTo(n): result = (n * (n + 1)) / 2 return result # Now lets see how well this works t = sumTo(0) print("The sum from 1 to 0 is",t) t = sumTo(10) print("The sum from 1 to 10 is",t) t = sumTo(5) print("The sum from 1 to 5 is",t) ``` [Show Comments](#disqus_thread) 8. Write a function areaOfCircle(r) which returns the area of a circle of radius r. Make sure you use the math module in your solution. ```python def areaOfCircle(r): # your code here ===== from unittest.gui import TestCaseGui class myTests(TestCaseGui): def testOne(self): self.assertAlmostEqual(areaOfCircle(5.0),78.53981633974483,5,"Tested input: areaOfCircle(5.0)") self.assertEqual(areaOfCircle(5.0),78.53981633974483,"Tested input: areaOfCirlce(5.0)") self.assertEqual(areaOfCircle(0),0.0,"Tested input: areaOfCirlce(0)") self.assertAlmostEqual(areaOfCircle(31415.926535897932),3100627668.0299816,5,"Tested input: areaOfCirlce(31415.926535897932)") myTests().main() ``` 9. Write a non-fruitful function to draw a five pointed star, where the length of each side is 100 units.  ```python import turtle def drawFivePointStar(t): for i in range(5): t.forward(100) t.left(216) wolfram = turtle.Turtle() drawFivePointStar(wolfram) ``` [Show Comments](#disqus_thread) 10. Extend your program above. Draw five stars, but between each, pick up the pen, move forward by 350 units, turn right by 144, put the pen down, and draw the next star. You’ll get something like this (note that you will need to move to the left before drawing your first star in order to fit everything in the window):  What would it look like if you didn’t pick up the pen? 11. Extend the star function to draw an n pointed star. (Hint: n must be an odd number greater or equal to 3). ```python import turtle def drawStar(t, n): for i in range(n): t.forward(100) t.left(180 - 180/n) stroustrup = turtle.Turtle() drawStar(stroustrup, 7) ``` [Show Comments](#disqus_thread) 12. Write a function called drawSprite that will draw a sprite. The function will need parameters for the turtle, the number of legs, and the length of the legs. Invoke the function to create a sprite with 15 legs of length 120. 13. Rewrite the function `sumTo(n)` that returns the sum of all integer numbers up to and including n. This time use the accumulator pattern. ```python def sumTo(n): # your code here ===== from unittest.gui import TestCaseGui class myTests(TestCaseGui): def testOne(self): self.assertEqual(sumTo(15),120,"Tested sumTo on input 15") self.assertEqual(sumTo(0),0,"Tested sumTo on input 0") self.assertEqual(sumTo(25),325,"Tested sumTo on input 25") self.assertEqual(sumTo(7),28,"Tested sumTo on input 7") myTests().main() ``` ```python def sumTo(n): sum = 0 for i in range(1,n+1): sum = sum + i return sum # Now lets see how well this works t = sumTo(0) print("The sum from 1 to 0 is",t) t = sumTo(10) print("The sum from 1 to 10 is",t) t = sumTo(5) print("The sum from 1 to 5 is",t) ``` [Show Comments](#disqus_thread) 14. Write a function called `mySqrt` that will approximate the square root of a number, call it n, by using Newton’s algorithm. Newton’s approach is an iterative guessing algorithm where the initial guess is n/2 and each subsequent guess is computed using the formula: newguess = (1/2) \* (oldguess + (n/oldguess)). ```python def mySqrt(n): # your code here ===== from unittest.gui import TestCaseGui class myTests(TestCaseGui): def testOne(self): self.assertAlmostEqual(mySqrt(4.0),2.0,0,"Tested mySqrt on input 4.0") self.assertAlmostEqual(mySqrt(9.0),3.0,4,"Tested accuracy of mySqrt on input 3.0") self.assertAlmostEqual(mySqrt(36.0),6.0,5,"Tested accuracy of mySqrt on input 6.0") self.assertAlmostEqual(mySqrt(100.0),10.0,4,"Tested accuracy of mySqrt on input 10.0. Try iterating more times.") myTests().main() ``` 15. Write a function called `myPi` that will return an approximation of PI (3.14159…). Use the [Leibniz](http://en.wikipedia.org/wiki/Leibniz_formula_for_%CF%80) approximation. ```python def myPi(iters): # Calculate an approximation of PI using the Leibniz # approximation with iters number of iterations # your code here ``` ```python def myPi(iters): ''' Calculate an approximation of PI using the Leibniz approximation with iters number of iterations ''' pi = 0 sign = 1 denominator = 1 for i in range(iters): pi = pi + (sign/denominator) sign = sign * -1 # alternate positive and negative denominator = denominator + 2 pi = pi * 4.0 return pi pi_approx = myPi(10000) print(pi_approx) ``` [Show Comments](#disqus_thread) 16. Write a function called myPi that will return an approximation of PI (3.14159…). Use the [Madhava](http://en.wikipedia.org/wiki/Madhava_of_Sangamagrama) approximation. ```python def myPi(iters): # Calculate an approximation of PI using the Madhava # approximation with iters number of iterations #your code here ``` 17. Write a function called fancySquare that will draw a square with fancy corners (sprites on the corners). You should implement and use the drawSprite function from above. For an even more interesting look, how about adding small triangles to the ends of the sprite legs. ```python import turtle def drawSprite(t, numlegs, leglength): angle = 360/numlegs for i in range(numlegs): t.forward(leglength) t.backward(leglength) t.left(angle) def drawFancySquare(t, sz, lgs, lgl): for i in range(4): t.forward(sz) drawSprite(t, lgs, lgl) t.left(90) wn = turtle.Screen() wn.bgcolor("lightgreen") alex = turtle.Turtle() drawFancySquare(alex, 100, 10, 15) wn.exitonclick() ``` [Show Comments](#disqus_thread) 18. There was a whole program in [A Turtle Bar Chart](ATurtleBarChart.html#bar-chart) to create a bar chart with specific data. Creating a bar chart is a useful idea in general. Write a non-fruitful function called barChart, that takes the numeric list of data as a parameter, and draws the bar chart. Write a full program calling this function. The current version of the `drawBar` function unfortuately draws the top of the bar through the bottom of the label. A nice elaboration is to make the label appear completely above the top line. To keep the spacing consistent you might pass an extra parameter to `drawBar` for the distance to move up. For the `barChart` function make that parameter be some small fraction of `maxheight+border`. The fill action makes this modification particularly tricky: You will want to move past the top of the bar and write before or after drawing and filling the bar. ```python import turtle def drawBar(t, height): """ Get turtle t to draw one bar, of height. """ t.begin_fill() # start filling this shape t.left(90) t.forward(height) t.write(str(height)) t.right(90) t.forward(40) t.right(90) t.forward(height) t.left(90) t.end_fill() # stop filling this shape xs = [48, 117, 200, 240, 160, 260, 220] # here is the data maxheight = max(xs) numbars = len(xs) border = 10 wn = turtle.Screen() # Set up the window and its attributes wn.setworldcoordinates(0-border, 0-border, 40*numbars+border, maxheight+border) wn.bgcolor("lightgreen") tess = turtle.Turtle() # create tess and set some attributes tess.color("blue") tess.fillcolor("red") tess.pensize(3) for a in xs: drawBar(tess, a) wn.exitonclick() ```