Lecture 5 — Python Functions =============================== Reading ------- Most of this is covered late in Chapter 2 of *Practical Programming* and Chapter 3 of *Think Python*. Chapter 6 of *Think Python* goes into more detail, but we are not quite ready for that yet. Why Functions? --------------- - The purpose of today’s class is to introduce the basics of writing and running Python functions. - Recall Lab 1 for computing disk size. We had to repeat the same computation three times for different input. - It is easy to find a mistake and forget to fix it in all copies of the same code. - It is also hard to distinguish between the same code repeated three times and three different computations. - Programmer's motto: DRY -- don't repeat yourself. - Define it once and use it multiple times. - Functions are extremely useful for writing complex programs: - They divide complex operations into a combination of simpler steps. - They make programs easier to read and debug by abstracting out frequently repeated code. Functions ---------- - A function - Takes as input one or more arguments. - Computes a new value, a string or a number. - Returns the value, so that it can be assigned to a variable or output. - Let's see this with a built-in function: :: >>> len('RPI Puckman') 11 Can you identify the input argument, the computation and the returned value? A Function to Compute the Area of a Circle ------------------------------------------ - In mathematics, many functions are given as formulas. You might write a function to calculate the area of a circle as .. math:: a(r) = \pi r^2 - In Python, when typing directly into the interpreter, we write :: >>> def area_circle(radius): ... pi = 3.14159 ... area = pi * radius**2 ... return area - Then we can run this using :: >>> area_circle(1) >>> area_circle(2) >>> r = 75.1 >>> area_circle(r) Note that by using examples with small values for the radius we can easily check that our function is correct. - Important syntax includes - Use of the keyword ``def`` and the ``:`` to indicate the start of the function - Indentation for the lines after the ``def`` line - Blank line at the end of the function The ``...`` are produced by the Python interpreter, just like the ``>>>`` are. What does Python do as we type? ------------------------------- #. Reads the keyword ``def`` and notes that a function is being defined. - The line that starts with ``def`` is called the function *header* #. Reads the rest of the function definition, checking its syntax #. Notes the end of the definition when the blank line is reached. #. Sees the function call :: >>> area_circle(1) at what’s known as the “top level” or “main level” of execution (indicated by the presence of ``>>>``), and - Jumps back up to the function - Assigns 1 to the parameter ``radius`` - Runs the code inside the function - Returns the result of the calculation back to the top level and outputs the returned result #. Repeats the process of running the function at the line :: >>> area_circle(2) this time with ``radius`` assigned the value 2 #. Repeats the process again at the line :: >>> area_circle(r) and uses the value of the variable ``r`` which is 75.1. Flow of Control --------------- - To re-iterate, the “flow of control” of Python here involves - Reading the function definition without executing - Seeing a ''call'' to the function, jumping up to the start of the function and executing - Returning back to the place in the program that called the function and continuing. - Functions can compute many different things and return any data type Python supports. Arguments, Parameters and Local Variables ----------------------------------------- - *Arguments* are the values 1, 2 and 75.1 in our above examples. - These are each passed to the *parameter* called ``radius`` named in the function header. This parameter is used just like a variable in the function. - The variable ``pi`` and ``area`` are *local variables* to the function (though we should probably use the ``math`` module for pi in the future). - Neither ``pi`` nor ``radius`` or ``area`` exists at the top / main level. At this level, they are ''undefined variables''. Try it out. Exercise --------- #. Write a function to convert the Celsius temperature to a Fahrenheit temperature and return it. :: >>> to_celsius(90) 32.22 #. Write a function that takes as input a string and returns a new string that frames it with ``*``s. :: >>> frame_word('spam and eggs') '*****************\n* spam and eggs *\n*****************' >>> print frame_word('spam and eggs') ***************** * spam and eggs * ***************** Storing Your Function In a Python File -------------------------------------- - In practice we rarely type our functions directly into the interpreter. Instead, we type the function into a file along with the rest of the program, save the file, and then run the program. - This is what happens when you type into the upper pane of the Wing IDE display. - We run the program by clicking on the green triangle. The results appear in the "Python Shell" on the lower right. - The flow of control is the same as if we typed directly into the interpreter, but... - We need ``print`` statements to generate the output - We do not need the blank line to end the function definition. We just need to stop the indentation. - We will analyze the following program in class. :: import math def area_circle(radius): area = math.pi * radius**2 return area r = 2 a = area_circle(r) print "Area of a circle with radius: %.1f is %.1f" %(r, a) Functions with Multiple Arguments / Parameters ---------------------------------------------- - For our volume calculation, we write a function involving two parameters, called with two arguments: :: import math def volume(radius, height): return math.pi * radius ** 2 * height print "volume of cylinder with radius", 1, "and height 2 is", volume(1,2) print "volume of cylinder with radius", 2, "and height 1 is", volume(2,1) - Python determines which argument goes to which parameter based on the order of the arguments, the first going to ``radius`` and the second going to ``height``. Exercises --------- For the following problems, write your code as though it is being typed into a file (or, if you have your laptop, type it into a file in the upper left corner of the Wing IDE). #. Write a function to convert from Fahrenheit to Celsius. Then, below the function, write code that reads a Fahrenheit value, calls the function to make the conversion, and prints the result. #. Write a function that computes the area of a rectangle. Then, write code to demonstrate the use of this function. #. Write a function that returns the middle value among three integers. (Hint: make use of :func:`min` and :func:`max`.) Write code to test this function with different inputs. For each program, identify the arguments, the parameters, the local variables and the global variables. More on program structure ------------------------- - Let us revisit the program structure that will allow us to write readable programs. - First a general comment describing the program. - Second, all import statements. - Third, all function definitions. - Now, you can have the main body of your program, generally involves reading or defining variables first, computation (including calling functions) and output. - Well structured programs are easy to read and debug. We will work hard to help you develop good habits early on. Functions That Do Not Return Values ----------------------------------- - Some Python functions do not return a value — usually they print out their result. - For example, :: import math def volumep(r, h): vol = math.pi * r ** 2 * h print "The volume of a cylinder with radius", r, "and height", h, "is", vol volumep(1,2) volumep(2,1) - The end of the function is indicated by the line starting at ``volumep(1,2)``, which is at the **same level of indentation** as the ``def``. - There is no ``return`` and the calling code does not attempt to use (e.g. print) a returned value. - We could add a ``return`` with no value at the end of the function. - Try and see what happens if you typed: :: >>> print volumep(1,2) - The choice between using functions that do and do not have return values will become clear over time. Functions That Call Functions ----------------------------- - Let’s make use of our area of circle function to compute the surface area of the cylinder. - Here is the Python code, in file ``surface_area.py``: :: import math def area_circle(radius): return math.pi * radius ** 2 def area_cylinder(radius,height): circle_area = area_circle(radius) height_area = 2 * radius * math.pi * height return 2*circle_area + height_area print 'The area of a circle of radius 1 is', area_circle(1) r = 2 height = 10 print 'The surface area of a cylinder with radius', r print 'and height', height, 'is', area_cylinder(r,height) - Now we’ve defined two functions, one of which calls the other. - Flow of control proceeds in two different ways here: #. Starting at the first ``print`` at the top level, into ``area_circle`` and back. #. At the third ``print`` #. into ``area_cylinder``, #. into ``area_circle``, #. back to ``area_cylinder``, and #. back to the top level. - The Python interpreter keeps track of where it is working and where to return when it is done with a function, even if it is back into another function. Thinking About What You See --------------------------- Why is it NOT a mistake to use the same name, for example ``radius``, in different functions (and sometimes at the top level)? Let’s Make Some Mistakes ------------------------ In order to check our understanding, we will play around with the code and make some mistakes on purpose - Removing ``math`` from ``math.pi`` in one definition - Changing the name of a function - Switching the order of the parameters in a function call - Making an error in our calculation Exercise -------- #. Write a function to compute the area of a rectangle. #. Write a second function that takes the length, width and height of a rectangular solid and computes its surface area. It should use the function you wrote to compute the area of the rectangle, calling it three times. Why Functions? -------------- We write code that is - Easier to think about and write - Easier to test: we can check the correctness of ``area_circle`` before we test ``area_cylinder``. - Clearer for someone else to read - Reusable in other programs Together these define the notion of *encapsulation*, another important idea in computer science! Summary ------- - Functions for encapsulation and reuse - Function syntax - Arguments, parameters and local variables - Flow of control, including functions that call other functions - Built-in functions - You can find the code developed in this class under the class modules. In particular, :mod:`area_solid` and :mod:`area_volume`. What to work on before next class: ---------------------------------- Concepts to review before next class: - **Expressions:** What type of data do they return? - Try typing simple math formula to the Python interpreter:: >>> 1 + 2 * 3 / 3 * 4**2 **3 - 3 / 3*4 and manually find the output. Don't be fooled by the spaces! Operator precedence is in effect. Try writing your own expressions. - **Variables:** Do you know what are valid and invalid variable names? - What is the difference in the output between:: >>> 3 + 4 >>> print 3 + 4 >>> x = 3 + 4 >>> print x >>> print x = 3+4 Try to guess before typing it in, but make a habit of typing simple statements like this and looking at the result. - **Assignment:** Can you trace the value of a variable after many different assignments? Don't be fooled by the name of variables. Try to do it manually:: >>> one = 2 >>> two = 1 >>> three = 4 >>> one += 3 * two >>> two -= 3 * one + three By the way, make a habit of picking nice variable names. Your variables should be meaningful whenever possible both to you and to anyone else reading your code. - **Functions:** Write the functions from class on your own using the Python interpreter. Try to do it without looking at notes. Can you do it? - Write a function that returns a value. - Write a function with no return. - Write a function where ``return`` is not the last statement in the function. - Call these functions by either printing their result or assigning their results to a value. Here, I'll get you started. :: def regenerate_doctor(doctor_number): return doctor_number+1 def regenerate_tardis(doctor_number): print "Tardis is now ready for doctor number", doctor_number def eliminate_doctor(doctor_number): return 0 print "You will be eliminated doctor", doctor_number - Write functions that use the built-in functions. Make sure you memorize what they are and how they are used. - Finally, write some functions to a file and execute them from within the file. Now, execute the file. By next class, make sure all of this is quite easy to do without consulting the course notes.