Chapter 5. Functions

A function is a reusable chunk of code. It is a block of code with a name that takes input, provides output, and can be stored in files for later use. Pretty much any useful piece of Python code is stored in a function.

Python has excellent support for functions. For instance, it provides many ways to pass data into a function. It also lets you include documentation strings within the function itself so that you—or other programmers—can always read how the function works.

Once we learn about functions, we will be using them constantly. Thus it is important that you have a good grasp of how they work. As we will soon see, we must master a handful of details in order to completely understand functions. With practice, these details soon become second nature, so be sure to try out the examples from this chapter.

Calling Functions

We’ve been calling functions quite a bit so far, so let’s take a moment to look a little more carefully at a function call.

Consider the built-in function pow(x, y), which calculates x ** y—that is to say, x raised to the power y:

>>> pow(2, 5)
32

Here, we say that pow is the function name, and that the values 2 and 5 are arguments that are passed into pow. The value 32 is the return value, so we say that pow(2, 5) returns 32. Figure 5.1 gives a high-level overview of a function call.

It’s often useful to think of functions as being black boxes that accept an input (2 and 5 in this case) and return an output (32). From the point of view of a programmer calling the pow function, there is no (easy) way to see inside of pow. All we know is what the documentation tells us, and what the function does when we call it.

Figure 5.1. It’s often useful to think of functions as being black boxes that accept an input (2 and 5 in this case) and return an output (32). From the point of view of a programmer calling the pow function, there is no (easy) way to see inside of pow. All we know is what the documentation tells us, and what the function does when we call it.

When you call a function within an expression, Python essentially replaces the function call with its return value. For example, the expression pow(2, 5) + 8 is the same as 32 + 8, which evaluates to 40.

When a function takes no input (that is to say, it has zero arguments), you must still include the round brackets () after the function name:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__']

The () tells Python to execute the function. If you leave off the (), then you get this:

>>> dir
<built-in function dir>

Without the (), Python does not execute the dir function and instead tells you that dir labels a function. The underlying idea of function names and variable names is the same: A function name labels a special function object, while a variable name labels data (such as strings or numbers).

Functions that don’t return a value

Some functions, such as print, are not meant to return values. Consider:

>>> print('hello')
hello
>>> x = print('hello')
hello
>>> x
>>> print(x)
None

Here the variable x has been assigned a special value called None. None indicates “no return value”: It is not a string or a number, so you can’t do any useful calculations with it.

Reassigning function names

You need to take care not to accidentally make a built-in function name refer to some other function or value. Unfortunately, Python never stops you from writing code like this:

>>> dir = 3
>>> dir
3
>>> dir()
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    dir()
TypeError: 'int' object is not callable

Here we’ve made dir label the number 3, so the function object that dir used to refer to is no longer accessible! It has disappeared, and will only return once you restart Python.

On the plus side, the ability to reassign function names this way allows you to play advanced tricks like rewriting built-in functions. But we won’t be doing any of that in this book—we’ll always leave the built-in functions as they are.

Defining Functions

Now we turn to creating our own functions. As an example, let’s write a function to calculate the area of a circle. Recall that a circle’s area is pi times its radius squared. Here is a Python function that does this calculation:

# area.py
def area(radius):
    """ Returns the area of a circle with the given radius.
    For example:

    >>> area(5.5)
    95.033177771091246
    """
    import math
    return math.pi * radius ** 2

Save this function inside a Python file (area.py would be a good name); then load it into the IDLE editor and run it by pressing F5. If everything is typed correctly, a prompt should appear and nothing else; a function is not executed until you call it. To call it, just type the name of the function, with the radius in brackets:

>>> area(1)
3.1415926535897931
>>> area(5.5)
95.033177771091246
>>> 2 * (area(3) + area(4))
157.07963267948966

The area function can be called just like any other function, the difference being that you have written the function and so you have control over what it does and how it works.

Parts of a function

Let’s look at each part of the area function. The first line, the one that begins with def, is called the function header; all the code indented beneath the header is called the function body.

Function headers always begin with the keyword def (short for definition), followed by a space, and then the name of the function (in this case, area). Function names follow essentially the same rules as names for variables.

After the function name comes the function parameter list: This is a list of variable names that label the input to the function. The area function has a single input, radius, although a function can have any number of inputs. If a function has 0 inputs, then only the round brackets are written, ().

Finally, like loops and if-statements, a function header ends with a colon (:).

After the function header comes an optional documentation string, or doc string for short. A doc string contains documentation for the programmer. It briefly explains what the function will do, and it may include examples or other helpful information. While doc strings are optional, they are almost always a good idea: When you start writing a lot of functions, it is easy to forget exactly what they do and how they work, and a well-written doc string can be a good reminder.

After the doc string comes the main body of the function. This is simply an indented block of code that does whatever you need it to do. The code in this block is allowed to use the variables from the function header. Just as with if-statements and loops, the beginning and end of the body block are marked using consistent indentation.

Finally, the function should return a value using the return keyword. When a return statement is executed, Python jumps out of the function and back to the point in the program where it was called.

In the case of the area function, the return statement is the last line of the function, and it simply returns the value of the area of a circle using the standard formula. Note that it uses the radius parameter in its calculation; the value for radius is set when the area function is called either elsewhere in the program or at the interactive command line.

A return is usually the last line of a function to be executed (the only time it isn’t is when the function ends unexpectedly due to an exception being thrown, which we will talk about in a later chapter). You can put a return anywhere inside a function body, although it is typically the last physical line of the function.

A function is not required to have an explicit return statement. For example:

# hello.py
def say_hello_to(name):
    """ Prints a hello message.
    """
    cap_name = name.capitalize()
    print('Hello ' + cap_name + ', how are you?')

If you don’t put a return anywhere in a function, Python treats the function as if it ended with this line:

return None

The special value None is used to indicate that the function is not meant to be returning a useful value. This is fairly common: Functions are often used to perform tasks where the return values don’t matter, such as printing output to the screen.

Variable Scope

An important detail that functions bring up is the issue of scope. The scope of a variable or function is where in a program it is accessible, or visible. Consider these two functions:

# local.py
def dist(x, y, a, b):
    import math
    s = (x - a) ** 2 + (y - b) ** 2
    return math.sqrt(s)

def rect_area(x, y, a, b):
    width = abs(x - a)
    height = abs(y - b)
    return width * height

Any variable assigned for the first time within a function is called a local variable. The function dist has one local variable, s, while rect_area has two local variables, width and height.

The parameters of a function are also considered local. Thus dist has a total of five local variables—x, y, a, b, and s; rect_area has a total of six. Notice that variables x, y, a, and b appear in both functions, but they generally label different values.

Importantly, local variables are usable only within the function they are local to. No code outside of the function can access its local variables.

When a function ends, its local variables are automatically deleted.

Global variables

Variables declared outside of any function are called global variables, and they are readable anywhere by any function or code within the program. However, there is a wrinkle in reassigning global variables within functions you need to be aware of. Consider the following:

# global_error.py
name = 'Jack'

def say_hello():
    print('Hello ' + name + '!')

def change_name(new_name):
    name = new_name

The variable name is a global variable because it is not declared inside any function. The say_hello() function reads the value of name and prints it to the screen as you would expect:

>>> say_hello()
Hello Jack!

However, things don’t work as expected when you call change_name:

>>> change_name('Piper')
>>> say_hello()
Hello Jack!

Nothing changed—name still labels the value 'Jack'. The problem is that Python treated name inside the change_name function as being a local variable, and so ignored the global name variable.

To access the global variable, you must use the global statement:

# global_correct.py
name = 'Jack'

def say_hello():
    print('Hello ' + name + '!')

def change_name(new_name):
    global name
    name = new_name

This makes all the difference. Both functions now work as expected:

>>> say_hello()
Hello Jack!
>>> change_name('Piper')
>>> say_hello()
Hello Piper!

Using a main Function

It is usually a good idea to use at least one function in any Python program you write: main(). A main() function is, by convention, assumed to be the starting point of your program. For instance, it’s convenient to write the password program we saw in the previous chapter using a main function

# password2.py
def main():
    pwd = input('What is the password? ')
    if pwd == 'apple':
        print('Logging on ...')
    else:
        print('Incorrect password.')

    print('All done!')

Notice that all the code is indented underneath the main function header.

When you run password2.py in IDLE, nothing happens—only the prompt appears. You must type main() to execute the code within in it.

The advantage of using a main function is that it is now easier to rerun programs and pass in input values.

Function Parameters

Parameters are used to pass input into a function, and Python has several kinds of parameters. First, though, we will look at the common way that all parameters are passed in Python.

Pass by reference

Python passes parameters to a function using a technique known as pass by reference. This means that when you pass parameters, the function refers to the original passed values using new names. For example, consider this simple program:

# reference.py
def add(a, b):
   return a + b

Run IDLE’s interactive command line and type this:

>>> x, y = 3, 4
>>> add(x, y)
7

After you set x and y in the first line, Python’s memory looks like Figure 5.2. Now when add(x, y) is called, Python creates two new variables, a and b, that refer to the values of x and y (Figure 5.3). The values are assigned in the order they occur—thus a refers to x because x is the first argument. Notice that the values are not copied: They are simply given new names that the function uses to refer to them.

The state of memory after setting x to 3 and y to 4.

Figure 5.2. The state of memory after setting x to 3 and y to 4.

The state of memory just after add(x, y) is called, and a and b have been set to refer to the values of x and y, respectively.

Figure 5.3. The state of memory just after add(x, y) is called, and a and b have been set to refer to the values of x and y, respectively.

After a and b are summed and the function returns, references a and b are automatically deleted. The original x and y are untouched throughout the entire function call.

An important example

Passing by reference is simple and efficient, but there are some things it cannot do. For example, consider this plausibly named function:

# reference.py
def set1(x):
    x = 1

The intention is that it will set x to be the value 1. But when you try it, it does not work as expected:

>>> m = 5
>>> set1(m)
>>> m
5

Surprisingly, the value of m has not changed. The reason why is a consequence of pass by reference. It’s helpful to break the example down into steps:

  1. Assign 5 to m.

  2. Call set1(m): Assign the value of x to the value of m (so now both m and x point to 5).

  3. Assign 1 to m. Now the situation is as shown in Figure 5.4.

    After x is assigned 1 in the function call set1(m), m is unchanged and still refers to its original value of 5. However, the local variable x has indeed been set to 1.

    Figure 5.4. After x is assigned 1 in the function call set1(m), m is unchanged and still refers to its original value of 5. However, the local variable x has indeed been set to 1.

  4. When the set1 function ends, x is deleted.

The variable m is simply not accessible within set1, so there is no way to change what it points to.

Default values

It’s often useful to include a default value with a parameter.

To use default parameters:

  • In your function header, assign a value to each parameter you want to have a default value. For example, here we have given the greeting parameter a default value of 'Hello':

    # greetings.py
    def greet(name, greeting = 'Hello'):
        print(greeting, name + '!')
  • You can now call greet in two distinct ways, either with or without the greeting parameter value:

    >>> greet('Bob')
    Hello Bob!
    >>> greet('Bob', 'Good morning')
    Good morning Bob!

✓ Tips

  • Default parameters are quite handy and are used all the time in Python.

  • A function can use as many default parameters as it needs, although no parameter without a default value can appear before a parameter with one.

  • An important detail about default parameters is that they are evaluated only once, the first time they are called. In complicated programs, this can sometimes be the source of subtle bugs, so it is useful to keep this fact in mind.

Keyword parameters

Another useful way to specify parameters in Python is by using keywords.

To use keyword parameters:

  • In the header of your function, give each parameter that you want to use as a keyword parameter a default value. For example:

    # shopping.py
    def shop(where = 'store',
             what = 'pasta',
             howmuch = '10 pounds'):
        print('I want you to go to the', where)
        print('and buy', howmuch, 'of', what + '.')
  • To use keyword parameters when calling a function, call the function using the keyword form param = value. For example:

    >>> shop()
    I want you to go to the store
    and buy 10 pounds of pasta.
    >>> shop(what = 'towels')
    I want you to go to the store
    and buy 10 pounds of towels.
    >>> shop(howmuch = 'a ton', what = 'towels')
    I want you to go to the store
    and buy a ton of towels.
    >>> shop(howmuch = 'a ton', what = 'towels', where = 'bakery')
    I want you to go to the bakery
    and buy a ton of towels.

Keyword parameters have two big benefits. First, they make the parameter values clear, and thus help to make your programs easier to read. Second, the order in which you call keyword parameters does not matter. Both of these are quite helpful in functions with many parameters; for such functions it can be difficult to remember the exact order in which to put the parameters, and what they mean.

Modules

A module is collection of related functions and assignments.

To create a Python module:

  • Create a .py file containing your functions and assignments. For example, here is a simple module for printing shapes to the screen:

    # shapes.py
    """A collection of functions
       for printing basic shapes.
    """
    CHAR = '*'
    
    def rectangle(height, width):
        """ Prints a rectangle.
        """
        for row in range(height):
            for col in range(width):
                print(CHAR, end = '')
            print()
    
    def square(side):
        """ Prints a square.
        """
        rectangle(side, side)
    
    def triangle(height):
        """ Prints a right triangle.
        """
        for row in range(height):
            for col in range(1, row + 2):
                print(CHAR, end = '')
            print()

    The only difference between this and a regular Python program is the intended use: A module is a toolbox of helpful functions that you can use when writing other programs. Thus a module usually does not have a main() function.

  • To use a module, you simply import it. For example:

    >>> import shapes
    >>> dir(shapes)
    ['CHAR', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'rectangle', 'square', 'triangle']
    >>> print(shapes.__doc__)
    A collection of functions
    for printing basic shapes.
    >>> shapes.CHAR
    '*'
    >>> shapes.square(5)
    *****
    *****
    *****
    *****
    *****
    >>> shapes.triangle(3)
    *
    **
    ***
  • You can also import everything at once:

    >>> from shapes import *
    >>> rectangle(3, 8)
    ********
    ********
    ********

Namespaces

A very useful fact about modules is that they form namespaces. A namespace is essentially a set of unique variable and function names. The names within a module are visible outside the module only when you use an import statement.

To see why this is important, suppose Jack and Sophie are working together on a large programming project. Jack is on the West Coast, and Sophie is on the East. They agree that Jack will put all his code in the module jack.py, and Sophie will put all her code into sophie.py. They work independently, and it turns out that they both wrote a function called save_file(fname). However, only the headers of their functions are the same; they do radically different things. Having two functions with the same name is fine because the functions are in different modules, so the names are in different namespaces. The full name of Jack’s function is jack.save_file(fname), and the official name of Sophie’s is sophie.save_file(fname).

Thus modules support independent development, by preventing name clashes. Even if you are not working with other programmers, name clashes can be an annoying problem in your own programs, especially as they get larger and more complex.

Of course, you can still run into name clashes as follows:

>>> from jack import *
>>> from sophie import *

These kinds of import statements essentially dump everything from each module into the current namespace, overwriting anything with the same name as they go. Thus, it is generally wise to avoid from . . . import * statements in larger programs.

 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.220.92