Python Statements and Functions

In this seventh part of a nine-part series on the Python language, we continue our discussion of statements and move on to functions. This article is excerpted from chapter four of the book Python in a Nutshell, Second Edition, written by Alex Martelli (O’Reilly; ISBN: 0596100469). Copyright © 2007 O’Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O’Reilly Media.

List comprehensions

A common use of a for loop is to inspect each item in an iterable and build a new list by appending the results of an expression computed on some or all of the items. The expression form known as a list comprehension lets you code this common idiom concisely and directly. Since a list comprehension is an expression (rather than a block of statements), you can use it wherever you need an expression (e.g., as an argument in a function call, in a return statement, or as a subexpression for some other expression).

A list comprehension has the following syntax:

  [ expression for target in iterable lc-clauses ]

target and iterable  are the same as in a regular for statement. You must enclose the expression  in parentheses if it indicates a tuple.

lc-clauses  is a series of zero or more clauses, each with one of the following forms:

  for target in iterable
if expressio

target and iterable  in each for clause of a list comprehension have the same syntax and meaning as those in a regular for statement, and the expression  in each if clause of a list comprehension has the same syntax and meaning as the expression  in a regular if statement.

A list comprehension is equivalent to a for loop that builds the same list by repeated calls to the resulting list’s append method. For example (assigning the list comprehension result to a variable for clarity):

  result1 = [x+1 for x in some_sequence]

is the same as the for loop:

  result2 = []
  for x in some_sequence:

Here’s a list comprehension that uses an if clause:

  result3 = [x+1 for x in some_sequence if x>23]

This list comprehension is the same as a for loop that contains an if statement:

  result4 = []
  for x in some_sequence:
      if x>23:

And here’s a list comprehension that uses a for clause:

  result5 = [x+y for x in alist for y in another]

This is the same as a for loop with another for loop nested inside:

  result6 = []
  for x in alist:
      for y in another:

As these examples show, the order of for and if in a list comprehension is the same as in the equivalent loop, but in the list comprehension, the nesting remains implicit.

{mospagebreak title=The break Statement}

The break statement is allowed only inside a loop body. When break executes, the loop terminates. If a loop is nested inside other loops, a break in it terminates only the innermost nested loop. In practical use, a break statement is usually inside some clause of an if statement in the loop body so that break executes conditionally.

One common use of break is in the implementation of a loop that decides whether it should keep looping only in the middle of each loop iteration:

  while True:                   # this loop can never terminate naturally
      x = get_next()
      y = preprocess(x)
      if not keep_looping(x, y): break
      process(x, y)

The continue Statement

The continue statement is allowed only inside a loop body. When continue executes, the current iteration of the loop body terminates, and execution continues with the next iteration of the loop. In practical use, a continue statement is usually inside some clause of an if statement in the loop body so that continue executes conditionally.

Sometimes, a continue statement can take the place of nested if statements within a loop. For example:

  for x in some_container:
      if not seems_ok(x): continue
      lowbound, highbound = bounds_to_test()
      if x<lowbound or x>=highbound: continue
      if final_check(x):

This equivalent code does conditional processing without continue:

  for x in some_container:
if seems_ok(x):
          lowbound, highbound = bounds_to_test()
          if lowbound <= x < highbound:
              if final_check(x):

Both versions function identically, so which one you use is a matter of personal preference and style.

The else Clause on Loop Statements

while and for statements may optionally have a trailing else clause. The statement or block under that else executes when the loop terminates naturally (at the end of the for iterator, or when the while loop condition becomes false), but not when the loop terminates prematurely (via break, return, or an exception). When a loop contains one or more break statements, you often need to check whether the loop terminates naturally or prematurely. You can use an else clause on the loop for this purpose:

  for x in some_container:
if is_ok(x): break         # item x is satisfactory, terminate loop
print "Warning: no satisfactory item was found in container"
x = None

{mospagebreak title=The pass Statement}

The body of a Python compound statement cannot be empty; it must always contain at least one statement. You can use a pass statement, which performs no action, as a placeholder when a statement is syntactically required but you have nothing to do. Here’s an example of using pass in a conditional statement as a part of somewhat convoluted logic to test mutually exclusive conditions:

  if condition1(x):
  elif x>23 or condition2(x) and x<5:
pass                       # nothing to be done in this case
  elif condition3(x):

Note that, as the body of an otherwise empty def or class statement, you may use a docstring, covered in "Docstrings" on page 72; if you do write a docstring, then you do not need to also add a pass statement, although you are still allowed to do so if you wish.

The try and raise Statements

Python supports exception handling with the try statement, which includes try, except, finally, and else clauses. A program can explicitly raise an exception with the raise statement. As I discuss in detail in "Exception Propagation" on page 126, when an exception is raised, normal control flow of the program stops, and Python looks for a suitable exception handler.

The with Statement

In Python 2.5, a with statement has been added as a more readable alternative to the try/finally statement. I discuss it in detail in "The with statement" on page 125.

{mospagebreak title=Functions} 

Most statements in a typical Python program are grouped and organized into functions (code in a function body may be faster than at a module’s top level, as covered in "Avoiding exec and from…import *" on page 486, so there are excellent practical reasons to put most of your code into functions). A function is a group of statements that execute upon request. Python provides many built-in functions and allows programmers to define their own functions. A request to execute a function is known as a function call. When you call a function, you can pass arguments that specify data upon which the function performs its computation. In Python, a function always returns a result value, either None or a value that represents the results of the computation. Functions defined within class statements are also known as methods. Issues specific to methods are covered in "Bound and Unbound Methods" on page 91; the general coverage of functions in this section, however, also applies to methods.

In Python, functions are objects (values) that are handled like other objects. Thus, you can pass a function as an argument in a call to another function. Similarly, a function can return another function as the result of a call. A function, just like any other object, can be bound to a variable, an item in a container, or an attribute of an object. Functions can also be keys into a dictionary. For example, if you need to quickly find a functions inverse given the function, you could define a dictionary whose keys and values are functions and then make the dictionary bidirectional. Here’s a small example of this idea, using some functions from module math, covered in "The math and cmath Modules" on page 365:

  inverse = {sin:asin, cos:acos, tan:atan, log:exp}
  for f in inverse.keys(): inverse[inverse[f]] = f

The fact that functions are ordinary objects in Python is often expressed by saying that functions are first-class objects.

The def Statement

The def statement is the most common way to define a function. def is a single-clause compound statement with the following syntax:

  def function-name(parameters):

function-name is an identifier. It is a variable that gets bound (or rebound) to the function object when def executes.

parameters  is an optional list of identifiers, known as formal parameters or just parameters, that get bound to the values supplied as arguments when the
function is called. In the simplest case, a function doesn’t have any formal parameters, which means the function doesn’t take any arguments when it is called. In this case, the function definition has empty parentheses after function-name .

When a function does take arguments, parameters contains one or more identifiers, separated by commas (,). In this case, each call to the function supplies values, known as arguments, corresponding to the parameters listed in the function definition. The parameters are local variables of the function (as we’ll discuss later in this section), and each call to the function binds these local variables to the corresponding values that the caller supplies as arguments.

The nonempty sequence of statements, known as the function body, does not execute when the def statement executes. Rather, the function body executes later, each time the function is called. The function body can contain zero or more occurrences of the return statement, as we’ll discuss shortly.

Here’s an example of a simple function that returns a value that is twice the value passed to it each time it’s called:

  def double(x):
      return x*2

Please check back next week for the continuation of this series.

Google+ Comments

Google+ Comments