Functions

In general, functions allow us to package up and parameterize commonly used functionality. Python provides three types of functions: ordinary functions, lambda functions, and methods. In this section, we will concentrate on ordinary functions, with a very brief mention of lambda functions; we will cover methods in Chapter 3.

In Python, every function has either "global" or "local" scope. Broadly speaking, global scope means that the function is visible within the file in which it is defined and is accessible from any file which imports that file. Local scope means that the function was defined inside another scope (e.g., inside another function) and is visible only within the enclosing local scope. We will not concern ourselves further with this issue here, but will return to it in Chapter 3.

Functions are defined using the def statement, using the syntax:

def functionName(optional_parameters): suite

For example:

def greeting():

print "Welcome to Python"

The function name must be a valid identifier. Functions are called using parentheses, so to execute the greeting() function we do this:

greeting() # Prints "Welcome to Python"

A function's name is an object reference to the function, and like any other object reference it can be assigned to another variable or stored in a data structure:

g = greeting g() # Prints "Welcome to Python"

This makes keeping lists or dictionaries of functions trivial in Python.

Functions that accept parameters can be given the parameter values by position ("positional arguments"), by name ("keyword arguments"; but nothing to do with the language's keywords), or by a combination of both. Let us look at a concrete example: Python does not provide a range() function that operates on floats, so we will create one ourselves.

def frange(start, stop, inc): result = [] while start < stop:

result.append(start) start += inc return result

If we call this function as frange(0, 5, 0.5) the list we get back is [0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5], as we expect.

Like normal Python variables, we do not specify types for our parameters. And since we have not given any default arguments, every parameter must be specified, otherwise we will get a TypeError exception. For those unfamiliar with default arguments, Python allows us to give values to parameters in a function's signature. Each such value is a "default argument", and it is used if the corresponding argument is not given when the function is called.

In many cases we create functions where one or more arguments will almost always have the same values. Python allows us to provide default arguments for such situations, and we have taken advantage of this to provide a default argument for the third parameter, as this revised def line shows:

This works fine; for example, we can now call frange(0, 5) to get [0, 1.0, 2.0, 3.0, 4.0] since the increment defaults to 1.0. In common with other languages that allow default arguments, Python does not permit a parameter without a default argument to follow one that has a default argument; so we could not have frange(start=0, 5). Nor does Python allow overloaded functions. Neither of these restrictions is ever a problem in practice, as we will see shortly when we discuss keyword arguments.

Unfortunately, our frange() function does not provide the same argument logic as range() provides. For range(), if one argument is given it is the upper bound, if two are given they are the lower and upper bounds, and if three are given they are the bounds and the step size. So we will create a final frange() function, which more carefully mimics range()'s behavior:*

def frange(arg0, arg1=None, arg2=None):

Returns a list of floats using range-like syntax frange(start, stop, inc) # start = arg0 stop = arg1 inc = arg2 frange(start, stop) # start = arg0 stop = arg1 inc = 1.0

II ii II

★For a more sophisticated frange(), see "Writing a range-like Function with Float Increments" in the Python Cookbook.

if arg2 is not None: # 3 arguments given start = arg0 stop = arg1 inc = arg2

elif arg1 is not None: # 2 arguments given start = arg0 stop = arg1 else: # 1 argument given stop = arg0 # Build and return a list result = []

while start < (stop - (inc / 2.0)): result.append(start) start += inc return result

Forexample,frange(5) returns [0.0, 1.0, 2.0, 3.0, 4.0],frange(5, 10) returns [5, 6.0, 7.0, 8.0, 9.0],and frange(2, 5, 0.5) returns [2, 2.5, 3.0, 3.5, 4.0, 4.5].

The loop condition is different from the one we used earlier. It is designed to prevent you from accidentally reaching the stop value due to floating-point rounding errors.

After the def line, we have a triple-quoted string—and the string is not assigned to anything. An unassigned string that follows a def statement—or that is the first thing in a .py or .pyw file or that follows a class statement, as we will see later on in Part I—is called a "docstring". It is the natural place to document functions. By convention, the first line is a brief summary, separated from the rest by a blank line.

In most of the examples shown in the rest of the book, we will omit the doc-strings to save space. They are included in the source code that accompanies the book where appropriate.

The use of None is a more convenient default than, say, 0 since 0 might be a legitimate upper bound. We could have compared to None using the syntax arg2 != None, but using is not is more efficient and better Python style. This is because if we use is we get identity comparison rather than value comparison, which is fast because we are just comparing two addresses and don't have to look at the objects themselves. Python has one global None object, so comparing with it using is or is not is very fast.

The parameters passed to Python functions are always object references. In the case of references to immutable objects like strings and numbers, we can treat the parameters as though they were passed by value. This is because if an immutable parameter is "changed" inside a function, the parameter is simply bound to a new object, and the original object it referred to is left intact.

Conversely, mutable objects, that is, parameters that are object references to mutable types like lists and dictionaries, can be changed inside functions. These parameter-passing behaviors are the same as in Java.*

All Python functions return a value. This is done either explicitly by using a return or yield statement (covered next), or implicitly, in which case Python will return None for us. Unlike C++ or Java, we are not tied down to specifying one particular return type: We can return any type we want since what we return is an object reference that is bound to a variable of any type. Python functions always return a single value, but because that value can be a tuple or a list or any other collection, for all practical purposes, Python functions can return any number of values.

Was this article helpful?

0 0
Tuberminator

Tuberminator

The main focus of this report is to show how to get involved in video marketing on the run, how to rank quickly on YouTube and Google using FREE semi-automatic tools and services. QUICKLY AND FREE. I will show methods and techniques I use to rank my videos, as well as free resources and tools to make video clips, to get backlinks and free traffic.

Get My Free Ebook


Post a comment