1-9 Writing Simple Functions

Why Functions?

So far we have had experience using some of Python’s built-in functions, but we have not created our own.  A function is a named group of statements that can receive values, perform a specific task, and return values.  For example, the built-in function int()performs one simple job: it converts data of type float or str and returns an integer result.

Rather than write a large program as one long sequence of statements, programmers break it down into numerous functions, each performing a specific job in the overall program.  These small functions can then be executed in the desired order to solve an overall problem.  This approach to problem-solving and design is called divide and conquer in computer science.

If you think about it, there are many advantages to using functions:

    1. Code Reuse: If a specific task is performed in several places in a program, a function can be written once to perform that operation and then executed whenever it is needed.  There is no need to “reinvent the wheel” each time.  Not only does this save a lot of time for programmers, but it also leads to more efficient (shorter) programs.
    2. Simpler Code: Programs broken down into functions tend to be simpler to understand than reading one long sequence of statements.  One doesn’t really need to understand how a function works internally, just what data it requires and what data it returns (e.g., int()) to be able to use it productively.
    3. Easier Debugging:  If each subtask is contained in its own function, then testing, isolating errors, and debugging become much easier because you can focus on one function at a time.
    4. Supports Teamwork:  When a program is split up into smaller subtasks, it makes it easier to share the work when programmers work in teams.

Defining and Calling Functions

Here’s an example of defining and calling a simple function in Python:

The first line of the code is called a function header.  The function header marks the beginning of a function definition.  It begins with the Python keyword def, followed by the name of the function, followed by a set of parentheses, followed by a colon (:).  In terms of the function name, the same rules as variables apply — please go back and review them.

Style Rule #5: Function Naming

Function names should follow the same five rules as variable names (see Style Rule #1). Because a function performs an action, it’s considered good style to use verbs in function names. For example, a function that figures out the high score in a game might be called calculate_high_score(). This makes it very clear what task the function performs.

Recall that a docstring is a triple-quoted string useful in documenting your code.  In this case, I’ve included a docstring (indented) in the first line of the function body to explain what the function does. As you know, docstrings are ignored by the Python interpreter, but they are very important for human beings (like me) reading (or marking) your code — hint.. hint…

Style Rule #6: Function Commenting

We’ll add more detail to this style rule next class, but for now: Every function that you write should include a docstring as the first line of the function body clearly explaining what the function does. Note that in some of my examples I may leave out function docstrings to keep the notes shorter in case you are printing them. Don’t attempt this yourself, I’m a trained professional! 8)

Following the function header and docstring, the next two lines form a block and are performed any time the function is executed.  A block is a set of statements that belong together as a group.  The Python interpreter requires each line of code in a block to be indented (with the same number of spaces or tabs) so that it knows where the block begins and ends. You can use either spaces or tabs when indenting a block, but don’t use both.  Doing so may confuse the Python interpreter and cause an error.  Most Python IDE’s (like Wing IDE 101) automatically indent the lines in a block for you.  The interpreter ignores blank lines within a block.

Style Rule #7: Block Indenting

It is considered good style to consistently use four (4) space indents in a block. Any more or less than this tends to make code harder to read.

A function definition specifies what a function does, but does not cause the function to execute.  To execute a function, you must call it.  In our example, the line:

causes the Python interpreter to jump to the print_chorus()function and execute the statement(s) in its block.  When the end of the block is reached, the interpreter returns (or jumps back) to the line of the program that called the function and resumes execution at that point.

By writing and calling functions, you practice what’s known as abstraction.  Abstraction lets you think about the big picture without worrying about the details.  So, in this program, I can just call the function print_chorus() without worrying about the details of displaying the text.  All I have to do is call the function with one line of code, and it gets the job done.

The example above has only one function, but it’s possible to define many functions in a program.  Python programmers commonly include a main() function that they call when the program starts.  The main() function then calls other functions in the program as they are needed.  The main() function contains the mainline logic of the program, which is the overall logic.  Here’s the same example, including a main() function.

In this case, when the program is executed, the main() function is called first by the Python interpreter.  The main() function executes, calling the print_chorus() function as needed.  When the main() function ends, the interpreter jumps back to the part of the program that called it.  There are no more statements after the original call to main() so the program ends.

Click here for a great tool to help you visualize how function calls work!

Cut-and-paste the code above into this handy online tool and click the Visualize Execution button.

Top-Down Design

Now that you know how functions work, let’s talk about how to design a program that uses functions.  Programmers use a technique called top-down design to break down a program into functions:

    1. The overall task that the program must perform is broken down into a series of subtasks.
    2. Each of the subtasks is examined to determine whether it can be further broken down into more subtasks.  This step is repeated until no more subtasks can be identified.
    3. Once all of the subtasks have been identified, they are written in code.

This process is called top-down design because programmers begin by looking at the topmost level of tasks that must be performed, and then break those down into lower levels of subtasks. This problem-solving technique is a divide and conquer approach.

So how do you know if you’ve done a good job defining your functions?  The most important principle with function design is that each function should perform a single, well-defined task.  Here are two questions to ask yourself:

    1. Was it easy to name the function?  If you had a hard time naming your function it either does not perform a well-defined task or perhaps does too many things.  For example, a function named get_points_and_calculate_then_display_average_score() should probably be three separate functions!
    2. Is your function more than one printed page (40-50 lines)?  If so, then you are probably trying to do too many subtasks at once.  See if you can break it down further.

Local Variables and Scope

Anytime you assign a value to a variable inside a function, you create a local variable.  A local variable belongs to the function in which it is created, and only statements inside that function can access the variable.  An error will occur if a statement in one function tries to access a local variable that belongs to another function, for example:

Also, as you might expect, you cannot attempt to use a local variable within its function before the variable has been assigned a value.  For example:

To fix this code, the assignment of 99 to val should occur before the print() function.

As these examples demonstrate, a variable’s scope is the part of a program in which a variable may be accessed.  The scope of a local variable is the function in which it was created.  More specifically, its scope starts at the line where it is created, until the end of the function block is reached.  As soon as your function is finished running, the value of all local variables defined within it are deleted from memory.  This may seem restrictive, but it’s actually very important!

Consider: A large program might have hundreds or thousands of variables, and it’s impossible to keep track of them all.  If your program is broken down into a bunch of functions, you only have to keep track of the variables inside your current function.  This means you can declare all the local variables you want/need, without having to worry about them interfering with local variables defined in other functions and causing unintended consequences.

Two different functions can have a local variable with the same name.  Even though the local variables have the same name, they have different scopes.  Each function has its own version of the variable.  Here’s an example:

You Try!

    1. Add the heading “1-9 Writing Simple Functions” to your learning journal and answer the following questions:
      1. Briefly explain the four main benefits of designing a program with functions.
      2. Name and describe the two parts of a function definition.
      3. Why must we always indent the code in a function, is it a Python syntax requirement or just considered good style?
      4. What happens to the flow of execution when a function is called?  What happens when the end of the function’s block is reached?
      5. Where is a local variable defined, and what is its scope?
      6. Is it permissible to use the same local variable name in two different functions?  Explain why or why not.  Write an example program.