Source

Functions

Introduction to Functions

In Python, functions are defined using the def statement. The following example defines a function called get_word(). get_word() will take two parameters: a string sentence and a number N, and returns the N’th word of sentence.

import string

def get_word(sentence, N):
   words = string.split(sentence)
   return words[N]

The return statement, when followed by an expression, causes the value of the expression to be returned as the result of the function. In the above example, words[N] is returned as the result.

Python functions always produce a result, whether the code contains a return statement or not. If the path of execution falls off the end of the function, None is returned. A lone return statement, not followed by an expression, also returns None.

Default values for parameters can be specified by placing a “=” and an expression or a literal value after the parameter name. (For a discussion of using expressions to specify a default value, see the next section.)

In the following example, the function’s filename parameter has no default value, the compresslevel argument has a default value of 9, and the fileobj parameter has a default value of None.

def open_file(filename,
             compresslevel = 9,
             fileobj = None):
   if fileobj is None:
       fileobj = open(filename, 'w')
   compressor = zlib.compressobj( compresslevel )

To call a function with keyword arguments that can be specified in any order, no special function definition is needed, though default arguments are often used in concert with keywords. The function call can simply give the names of function parameters, followed by an “=” and the desired value for the parameter. Given a function definition like f(a, b = ‘empty’, c=3.5), the following function calls are all legal:

f(1, 'new', 7.2)
f(1, c=7.2)           # Equivalent to f(1, 'empty', 7.2)
f(c=1, a=4, b='new')  # Equivalent to f(4, 'new', 1)

The following calls are all illegal:

f(b = 'new')    # No value provided for a
f(a = 4, 4)     # Non-keyword argument after keyword argument
f(4, b=1, c=3, b=1) # duplicate keyword argument b

Calling a Function with an Argument Tuple

Problem

You have a function in a variable F, and a tuple T containing its arguments. You wish to call F with the arguments T.

Solution

Use the built-in function apply():

result = apply(F, T)

Functions that don’t require any arguments can be called using an empty tuple. For example, time.time() doesn’t take any arguments, so it can be called like this:

curtime = apply( time.time, () )

If the function takes keyword arguments, you can also pass in a dictionary whose keys and values are the keyword arguments and their values.

# Equivalent to
#  menu.add_command(label = 'Open Help', command = window.show_help)
kw = {'label': 'Open Help',
     'command': window.show_help }

apply(menu.add_command, (), kw)

Discussion

One subtle point is that apply(F, T) is not the same as F(T). F(T) calls F with exactly one argument, the tuple T, while apply(F, T) calls F with T[0] as the first argument, T[1] as the second, and so forth. An empty tuple corresponds to calling the function with no arguments.

How do I use different functionality on different platforms with the same program?

Remember that Python is extremely dynamic and that you can use this dynamism to configure a program at run-time to use available functionality on different platforms. For example you can test the sys.platform and import different modules based on its value.

import sys
if sys.platform == "win32":
   import win32pipe
   popen = win32pipe.popen
else:
   import os
   popen = os.popen

Also, you can try to import a module and use a fallback if the import fails:

try:
   import really_fast_implementation
   choice = really_fast_implementation
except ImportError:
   import slower_implementation
   choice = slower_implementation

This is commonly used to write code which will use a faster C extension module if it’s installed, but will still work without the extension.

Ignoring Return Values from a Function

Some programming languages, such as the scripting language in MATLAB, allow calling a function and ignoring some of its return values. You need to do this in Python, ignoring some value returned from a function.

If the function returns a tuple, as done by most functions that return multiple results, treat the return value as a tuple and slice it to obtain the results that you need.

def get_rgb_colour(colour_name):
   # ... set R, G, B, to the values
   return R, G, B

# Get just the red component of a colour
tup = get_rgb_colour('teal')
R = tup[0]

This can be expressed more compactly, though less clearly, without a tuple variable as:

R = get_rgb_colour('teal')[0]

Yet another solution is to use a dummy variable name for the variables that aren’t of interest. _ is suggested as a short and rarely used name for this purpose.

R, _, _ = get_rgb_colour('methyl yellow')

For the sake of completeness, it should be mentioned that Perl supports an idiom for ignoring return values by assigning them to undef, the Perl counterpart of Python’s None. (This idiom is rarely actually used in Perl programs.) Don’t try the same thing in Python, which would be:

None, None, B = get_rgb_colour('da Vinci green')

This will run without errors, and B will get the expected value, but it also adds a new name to the local scope: None is now bound to some value. (Maybe that last sentence should end with a ‘!’) Later uses of None in the same code will retrieve the assigned value, not the Python None object. In short, if you use the above idiom in Perl, don’t attempt to use it in Python.

Passing Functions as Parameters

Problem

You wish to pass a function as an argument to another function.

Solution

Python is flexible enough to treat functions and methods in the same way as ordinary variables.

F = f.write
F(s)

is the same thing as:

f.write(s)

As a computer scientist would describe it, functions are first-class objects in Python. So, you can simply pass a function as one of the arguments:

def repeat_func(func, N, data):
   "Repeat a function N times"
   for i in range(N):
       data = func(data)
   return data

repeat_func(differentiate, 3, data)

It’s also possible to store functions in Python data structures, such as variables, lists, tuples, and class instances. For example, the following function takes a list of functions, and calls them all, from left to right.

def compose(func_list, data):
   for F in func_list:
       data = F(data)
   return data

Discussion

A common application of this is to keep a dictionary of handler functions, retrieving the function to call. The following toy example has a dictionary mapping command names to the functions that should be called:

def output_status():
   ...

def set_bf_mode():
   ...

... other function definitions ...

cmd_dict = {'status': output_status, 'brightfield', set_bf_mode,
    'darkfield': set_df_mode, 'icr': set_icr_mode}

def call_command(cmd_name):
   function = cmd_dict[cmd_name]
   function()

It’s not necessary to actually have a def statement in order to create a function. The lambda keyword is used to create small unnamed functions. The function is limited to a single expression, but that’s enough to be useful in many cases. A common use for lambda is in concert with built-in functions like map(), which loops over the elements of a list, performs a function on each list element, and returns a list containing the results.

>>> map(string.upper,
...     ["Here's", "a", "list", "of", "words"] )
["HERE'S", 'A', 'LIST', 'OF', 'WORDS']

lambda would be used if there’s no built-in function corresponding to what you need. For example, the following code would take the first character of every word in the list:

>>> map(lambda word: word[0],
...     ["Here's", "a", "list", "of", "words"] )
['H', 'a', 'l', 'o', 'w']

Here’s another example. In this case, a default argument is used to bind the f.write() method to the local variable wr, and added a newline before calling the write method.

ftp.retrlines("RETR sightings.txt",
             lambda s, wr = f.write: wr( s+"\n" ) )

Returning a Variable Number of Values

Problem

You want to have a function that returns more than one value as its result. For example, you may have a function that takes a colour name, and returns three numbers, the red, green, and blue values for that colour.

Solution

The simplest and most common solution is to return a tuple containing the different values:

def get_rgb_colour(colour_name):
   # ... set R, G, B, to the values
   return R, G, B

Discussion

An alternative solution, using a class instance to hold return values, is useful if you want to return very many values, or differing numbers of values in different cases. You would set instance values of the class instance, and then return the instance to the caller.

class RGBSetting: pass

def get_rgb_colour(colour_name):
   retval = RGBSetting()
   # ... set retval.R, retval.G, retval.B, to the values
   return retval

Using an Expression for a Default Parameter Value

If a default value is some expression, that expression is evaluated at the time the def statement is executed, not when the function is called. Consider the following example:

default_level = 9
def new_compressor(compresslevel = default_level):
   print 'Compression level:', compresslevel

new_compressor()   # Prints the default value
default_level = 2  # Will this change the default value?
new_compressor()

When this code is run, it will print:

Compression level: 9
Compression level: 9

Remember, def is an executable statement, binding the function’s name “new_compressor” to a function object. At that time, default_level has a value of 9, so that’s used as the default value of compresslevel. Subsequently changing the value of default_level has no effect on the default value of the function. It’s not possible to change the object that’s been defined as the default value. However, if an object is mutable and can be modified in place, as a list or dictionary can be, then any modification made to that object will change the default. Another example will make this clearer, I hope:

def modify_list(List = []):
   print 'Before:', id(List), List
   List.append( 1 )
   print 'After: ', id(List), List

Calling this function with modify_list() will output:

Before: 135048144 []
After:  135048144 [1]

The first number, the value of id(List), is an integer guaranteed to be unique for this object while the object exists, and is usually derived from the machine address at which the object resides. The value printed here will vary from run to run of the Python interpreter, but will remain the same in each execution. On the first call of modify_list(), the list object assigned as the default value is changed. A second, identical call will produce:

Before: 135048144 [1]
After:  135048144 [1, 1]

id(List) is the same on both function calls, so the same list object is assigned as the default value, but the contents of that object have been changed, which doesn’t affect the value returned by id(List). New users are often surprised by this behaviour, and wonder if it’s a bug in Python; it’s not, and follows consistently from Python treating everything as a reference.