Home ]Software ]Curriculum ]Hardware ]Community ]News ]Publications ]Search ]


This module is designed to introduce Python to those that have some experience with programming. This module introduces key concepts in Python. After completing this module, the reader will be ready to write their own robot controllers.

Pyro Module Python Introduction

Pyro allows you to write most of your robot programming in Python. This module is designed to introduce you to the Python language. This is not a general introduction to programming. We will assume that you are already familiar with computer programming and problem solving and have had some exposure to an object-oriented programming language.

Using the Python Interpreter

Starting Python

Presuming that Python is set up and installed properly on your system, starting Python only requires typing:

python

at the command line. This will open the interpreter in interactive mode (described below).

Interactive mode

In interactive mode, the user can issue any legal command to the Python interpreter. The interpreter replies with the output of those commands. The output of a few simple commands issued in interactive mode are shown below:

>>> 2+2
4
>>> 3*3*3
27

To exit interactive mode, type the end of file character (CTRL-D on UNIX systems and CTRL-Z on Windows systems).

Running Python on a file

To tell Python to execute commands in a text file, type the name of the file after the command invoking the Python interpreter. The interpreter will open, execute the commands in the input file, print the output generated on the terminal window, and terminate. For example, consider the file HelloWorld.py.



# HelloWorld.py contains a "Hello World!" program in Python. 
print "Hello World!"

[ download] [ edit]


The box below shows the command to invoke the Python interpreter on this file and the resulting output:

$ python HelloWorld.py
Hello World!

Including other files

In Python each source file is seen as a separate module. Including a source file corresponds to importing a module. Modules are imported using the import command. The import command has the following form:

import <module_name>

When Python encounters an import command, it searches in the directory where the currently running script resides for a source file with the module's name. Python then searches any directories listed in the environment variable PYTHONPATH. If no file corresponding to the requested module is found, Python throws an ImportError exception. If the file is found, however, Python reads and executes the contents of the file. Any output generated by these commands is displayed as the file is processed. Any identifiers defined within the file (e.g. variables, functions, and classes) are placed within a namespace identical to the module name. Identifiers contained within a namespace can be accessed through statements of the form:

<namespace>.<identifier>

As an example of this process, consider two source files A.py:


Protect your treasured investment with cheap static caravan insurance policies. Do you have a static caravan? Static caravans are also called mobile homes or trailers. They are prefabricated homes that are produced in factories and then transported to the web site where the proprietors will occupy it. Other nations use them for short-term accommodation on campsites.

See to [ caravan insurance]

If you only check out your caravan through the getaway year, you might not think it is important for you to insure your static caravan. On the other hand, that ought to not be the case. Even though you are gone, many points can transpire to your caravan. Do not permit on your own worry above what perhaps could transpire to your caravan though you are not all-around. Don't chance it.

Erase all worries by acquiring insurance policies for your static caravan. There are a lot of insurance policy providers on the marketplace vying for your company. You can conduct an on-line lookup for reputable and acceptable insurance firms. It is generally highly recommended to study the reputation and high quality of service of these firms. Make guaranteed to review estimates and policies so you will get the best deal achievable. Check out consumer evaluations and feedback as properly. Inquire among buddies, relatives and associates who could be familiar with diverse static caravan insurance plan providers and policies.

There are quite a few feasible risks and dangers your caravan can drop victim to. Older caravans may be at danger of water leaks on the roof. Wind injury can outcome in a substantial dent on your caravan. Branches or flying debris can also break the windows or walls of your caravan. Fire is an additional important danger. A policy to shield your expense would definitely be of excellent enable for these circumstances.

It's not only Mother Nature that you would have to be bothered about. Criminals also really like to target caravans, especially when they are empty. Thieves and burglars may well want to rob holiday getaway caravans because they assume no one particular is all around and they can quickly get away with it. You need to guarantee that your insurance policy covers theft as well. Not having insurance coverage, there might not be a likelihood for you to recover the stolen or broken things. There are insurance policy policies that can swap the stolen or damaged goods. Vandalism and accidental hurt are also issues. Damages may possibly be high priced to fix so it is sensible for static caravan entrepreneurs to get very good coverage.

Refer to [ caravan insurance quotes]

You may possibly also want to consider installing added protection features on your caravan to make confident that you are completely covered versus all unpleasant possibilities. Acquiring protection capabilities may well also aid lower your insurance policy premiums.

If you have a caravan that you and your relatives only check out through the vacations, make guaranteed to get it insured. Protect oneself and your household from the money damages brought about by environmental hazards or theft. Avoid the emotional and economic anxiety. Perform thorough research on the static caravan insurance plan policy that will match your needs. Static caravan insurance coverage will put your head at ease and put together you for untoward incidents.

Take a look at [ compare caravan insurance]


and B.py



# B.py 
print "Importing module B" 
b = 5 
bb = b*b

[ download] [ edit]


Finally, suppose there is another source file C.py in the same directory as A.py and B.py which imports modules A and B and then executes a few commands:



# C.py 
import A 
import B 
 
print A.a 
print A.aa 
print B.b 
print B.bb

[ download] [ edit]


If python C.py were entered at the command line, the output would be:

Importing module A
Importing module B
6
36
5
25

Two variations on the import statement are allowed. Identifiers in a module can be imported into a namespace different from the name of the module. In this case, the import command takes on the form:

import <module> as <alias>

Instead of entering namespace <module>, identifiers in the module enter namespace <alias>.

Alternately, an identifier can be imported into the namespace where the import directive is being executed. In this case, the import command takes the form:

from <module> import <identifier>

To import all identifiers in a module into the current namespace, use the statement:

from <module> import *

A new version of C2.py which illustrates these variations on the import statement is shown below:



# C2.py 
import A as D 
from B import * 
 
print D.a 
print D.aa 
print b 
print bb

[ download] [ edit]


When run, C2.py generates the same output as C.py.

Here's a handy trick: Want to run Python on a file and then enter interactive mode? Run Python with the -i flag and the system will stay in Python and give you the >>> prompt which allows you to interact with objects and variables created in the file.

Important: When you're using Python interactively you need to be careful when importing modules that you're also editing. When a module is first successfully imported, its contents is read in and executed. Further imports of this file merely allow those identifiers that were created during this file's execution to become visible in a particular namespace. If you modify the contents of the module and are also interacting with it via the >>> prompt, you'll need to do a reload to allow the changes you've made in the file to become visible. For example, if you've just modified C.py, issuing:

reload('C') 

would make these changes visible in your interactive session. Or suppose you had imported C via from C import *. Then you'd need to:

reload('C')
from C import *

Finally, suppose you'd modified A.py and were only using this through C.py. Then you'd need to:

reload('A')
reload('C')

In general, when editing multiple interdependent files, it is a good idea to restart python to ensure you're executing the most recent code.

Configuring Emacs for Use with Python

Some recent versions of Emacs and XEmacs come with a major mode for use with Python. To check if Python mode is installed and properly set up, open a file with a .py extension. (X)Emacs should detect the filename and automatically enter Python mode (if (X)Emacs is in Python mode, the word Python will appear in the message bar at the bottom of the screen and Python code will be automatically colorized).

If Python mode is not installed, installing it is relatively simple. The file and installation instructions are available from  here.

Basic Python Syntax

One of Python's distinguishing features is its use of white space instead of punctuation marks to indicate the control structure of various statements . Simple statements (those containing only one command) are separated by line breaks. Compound statements --- including control structures and class and function definitions --- contain a header, which is ended by a colon, followed by a body. The header controls the execution of the code in the body. All statements following the header are considered to be part of the body until a statement with the same indentation as the header is found. The basic structure of a compound statement follows:

<header>:
     <body>

Also note that any line beginning with a # is a comment.

Basic Data Types and Structures

Python is dynamically typed. As a result, variables are not declared before use and their types can change as new data are assigned to them. The assignment operator works in a manner similar to that in other languages except that if the variable being assigned to does not yet exist, it is created. Also note that, for each of the arithmetic operators (described below), an augmented assignment operator, e.g. +=, is provided.

Integers, Floats, and Booleans

Integers and floats behave much like integers and floats in other languages. A series of digits are integer literals. Any integer literal can be converted into a long integer literal by appending an L to the end of it. Floating point literals are sequences of digits containing a single period at some point within the sequence. Some examples of numeric literals are shown below:

42     #integer literal
42.1   #floating point literal
42L    #long integer literal

All arithmetic operators behave as expected, with a couple subtleties. First, unlike C and C++, the exponentiation operator is **, not ^. When the division operator / is used on two integers, the result is truncated; for this not to occur, at least one of the operands must have a floating point value. Floating point values can be created with an explicit cast, e.g., float(3.14), or by including a 1.0 multiplier or a 0.0 summand.

As of Python 2.3, boolean literals take on the values True and False. When a boolean operator is applied to another data type, it is evaluated as follows. Non-zero instances of built-in data types (including ints, long ints, floats, strings, lists, tuples, and dictionaries) evaluate to True. Integer, long integer and float zeros; empty strings, lists, tuples, and dictionaries; and None all evaluate to False. (None is a built-in name that is Python's equivalent to a null value.)

Operator Description
not Boolean NOT
and Boolean AND
or Boolean OR

The built-in function type can be used to find out what type an object has:

>>> x = 42
>>> type(x)
<type 'int'>
>>> type(x*3.1)
>>> b = not x
>>> print b
False
>>> type(b)
<type 'bool'>

Strings, Lists, and Tuples

Python provides three kinds of sequences. Strings are immutable sequences of characters. Tuples are immutable sequences and can hold data of any type. As an immutable sequence can't be modified, once you've created one, its individual elements cannot be assigned to. Lists, on the other hand, are mutable sequences and can hold data of any type.

String literals can be delimited in three different ways. " and ' are valid delimiters. A string delimited by double quote cannot contain a " and a string delimited by single quotes cannot contain a '. However, a string delimited by " can contain a ' and vice versa (you can also just escape a quote that you'd like to embed in the string via a \). Furthermore, strings delimited by " and ' cannot extend more than one line. Strings can also be delimited by three sets of quotation marks, """. Triple-quoted strings can extend over more than one line (the line breaks are interpreted as newline characters) and can contain both " and '.

Tuples and lists can easily be constructed from literals. Lists are surrounded by square brackets [ ] and tuples are surrounded by parentheses ( ). In both lists and tuples, items are separated by commas.

Examples of legal strings, lists, and tuples are shown below.

'Python can\'t\nbe beat!'         # single-quoted string

"Python can't\nbe beat!"          # single-quoted string

"""Python can't
be beat"""                       # triple-quoted string

(1,2,3,4)                        # tuple

[1,2,3,4]                        # list

The three sequences types present similar interfaces. Each allows concatenation with the + operator: if x and y are sequences, x+y returns a sequence with y appended to x. Additionally, a sequence can be "multiplied" by an integer using the * operator: if x is sequence and n is an integer x*n returns the sequence x repeated n times. Each can be indexed: the statement S[i] returns the i-th element item in S (indexing begins at 0). Each sequence also allows slicing: the extraction of a subsequence. The statement S[i:j] returns a slice of S, a subsequence containing a copy of the ith element through the j-1th element of S. Either i or j can be omitted. If i is omitted, the subsequence will start at the beginning of S. If j is omitted, the subsequence will end at the last element of S. Python also provides the in operator, which allows one to test for membership: if x is some item and S is a list, x in S returns True if and only if x is contained in the sequence S. The expression x not in S returns not (x in S). Finally, Python defines the function len, which returns the number of items in a sequence. Examples of each of these sequence operations are shown below.

>>> x = [1,2,3]  
>>> x+x                       # concatenate 
[1, 2, 3, 1, 2, 3]
>>> [x, [x, 333]]             # sequences can be nested
[1, 2, 3, [[1, 2, 3], 333]]
>>> x*3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> x[0:1]
[1]
>>> x[0:2]
[1, 2]
>>> x[-2:]                    # negative index begins at the end
[2, 3]
>>> x[:]                      # slices are often used because they create copies
[1, 2, 3]
>>> y = x[:]                  # like this
>>> 2 in x
1
>>> len(x)
3

The above example uses list sequences. Analogous behavior occurs if x is a tuple or a string --- check it out!

Tuples don't always need surrounding parentheses; although context dependent, commas alone are often sufficient. One covenience of tuples is that variable values can be swapped without using temporary storage:

>>> a = 'a'
>>> b = 'b'
>>> a, b
('a', 'b')
>>> (b, a) = (a, b)
>>> a, b
('b', 'a')

Because lists' are mutable, they have a more complex interface. For instance, in lists, indexed items can be assigned to: the expression S[i] = 6 assigns the i-th item in S the value 6. Similarly, a list can be assigned to a list slice. There is no requirement that the slice and the list being assigned to have the same length. For instance:

>>> l, r = [1, 2, 3], [4, 5]
>>> l[2:] = r
>>> l
[1, 2, 4, 5]

By assigning list r to a slice of list l, where r is longer than the slice of l, elements can be added to l. Elements can be deleted from r in a similar manner:

>>> l[:2] = []
>>> l
[4, 5]

Lists also provide the methods summarized below:

s.append(x) Appends element x to list s
s.count(x) Returns the number of times x appears in s
s.extend(t) Appends list t to list s
s.index(x) Returns the index of the first occurrence of x in s (throws an exception in x is not present)
s.insert(i, x) Inserts element x at index i
s.len(x) Returns the number of items in the list
s.pop([i]) Removes and returns the i-th item in s; if i is not given, removes and returns the last element
s.remove(x) Removes the first occurrence of x from s
s.reverse() Reverses the order of items in the list
s.sort([f]) Sorts items using f to compare them; if f is not given, a default comparison function is used

Dictionaries

Dictionaries provide an easy way to lookup items based on key values. In a dictionary, an expression x:y represents a key/value pair, where x is the key and y is the value. A dictionary is surrounded by curly braces. Key/value pairs are separated by commas. The value associated with a given key can be found by indexing the dictionary with that key using the [] operator. A new key/value pair can be simply added to the dictionary: merely assign the value to be added to the dictionary, indexed with the key to be added. Note: Python makes no guarantees about the order in which entries will be stored in the dictionary.

A few examples of these operations are shown below.

>>> y = {}                     # an empty dictionary
>>> x = {'a':1, 'b':2, 'c':3}  # starts with three elements
>>> x['a']
1
>>> x['d'] = 4                 # adds the mapping 'd':4 to the dictionary
>>> x['d']
4
>>> d = dict(a=5, b=6)         # another way to make a dictionary that doesn't require quotes
>>> print d
{'a': 5, 'b': 6}

Dictionaries also provide several methods:
d.copy() Returns a copy of dictionary d
k in d Returns True if the key k is in dictionary d and False otherwise
d.items() Returns a list of all the key/value pairs in d
d.keys() Returns a list of all keys in d
d.values() Returns a list of all values in d
d.iteritems() Returns an iterator over all the key/value pairs in d
d.iterkeys() Returns an iterator over all the keys in d
d.itervalues()Returns an iterator over all the values in d
d.get(k[,x]) Returns d[k] if k is in d, otherwise returns x (if x is not given, it returns None

Multi-Dimensional Arrays

Multi-dimensional arrays can be implemented using nested lists. One might be tempted to cascade copies like so:

>>> x = [[0] * 5] * 10     # DON'T DO THIS!

However, this results in 10 copies of the same 5-element array. For example, if you then take the same array and make a single change:

>>> x[0][0] = 1
>>> print x
[[1, 0, 0, 0, 0], 
 [1, 0, 0, 0, 0], 
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0],
 [1, 0, 0, 0, 0]]

One could instead write a function that creates a multi-dimensional array:

def ndim(n, *args):
     if not args:
        return [0]*n
     A = []
     for i in range(n):
         A.append(ndim(*args))
     return A
This function uses the *args syntax, which indicates that ndim can be called with a variable number of arguments. It also demonstrates how append can be used to create a list of lists.
x = ndim(5, 10)
x[0][0] = 1
print x
[[1, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0]]
Another solution is to use "list comprehension," which will be discussed later.

Alternately, the numpy package, available from  http://sourceforge.net/projects/numpy/, provides a class called array which implements multi-dimensional arrays. Note that an array can hold any type of object, not just numbers, but that each object in the array must have the same type.

Flow of Control

All flow of control statements fall into the category of compound statements described in the "Basic Python Syntax" section. Thus, each consists of a header followed by a series of indented statements.

If Statements

If statements take the form:
   if <test_1>:
          <body_1>
   elif <test_2>:
        <body_2>
   .
   .
   .
   elif <test_n>:
        <body_n>
   else:
        <body_n+1>

Note the elif contraction for "else if". Also, neither the elif nor the else clause is syntactically necessary. The operation of the if statement is straightforward. If <test_1> is true, then <body_1> executes. If no elif or else statements are present, execution proceeds after the end of the if block. If some are present, then each of the elif tests are evaluated until one is found which is true, at which point the associated body is executed. If none of the tests are true and an else clause is present, the body associated with the else clause is executed.

Looping Statements (for and while)

The while statement is similar to that in many other languages. It has the following syntactical form:
while <test>:
     <body>
As long as <test> continues to evaluate to True, the loop will continue to execute <body>.

The for statement in Python is designed for iteration over containers. Its syntax is:

for <var> in <container>:
     <body>
The following code snippet and its resulting output shows the typical use of a for loop:
>>>for char in "abcd":
...     print char
...
a
b
c
d

for loops provide easy iteration over containers. However, it is often desirable to execute the body of a loop some number of times and to have a variable inside the loop indicate which iteration is in progress. One option would be to create list containing integers from 1 to n, where n is the number of iterations desired, and then to iterate over that list. Python contains a command to do this called range. The range function takes from one to three arguments. When called with one argument --- e.g. range(x) --- it returns a list of integers from 0 to x-1. When called with two arguments --- e.g. range(x,y) --- it returns a list of integers from x up to and including y-1. Finally, when called with three arguments --- e.g. range(x,y,step) --- it returns a list starting at x and counting up by step. The downside of using range is that it must allocate a list. To avoid the memory allocation, Python provides the function xrange(x,[y,step]). xrange does not allocate a list, but interacts with a for loop in exactly the same manner as range.

The following code provides an example:

>>> for i in range(0,10,2):
...     print i
...
0
2
4
6
8
>>> for i in xrange(0,10,2):
...     print i
...
0
2
4
6
8

You can count backwards too:

>>> for i in range(10,0,-2):
...     print i
...
10
8
6
4
2

Notice that the second parameter is never reached. In this manner, it behaves like a C for-loop construct.

Functions

Function definitions are also compound statements. The function declaration syntax is as follows:

def <func_name>(<arg_name_1>,...,<arg_name_n>):
     <body>
return statements can be placed anywhere within a function. The function definition imposes no requirement that a function return data of a certain type. In fact, a function can have multiple return statements, each of which returns data of a different type! Similarly, no type requirements are imposed upon function arguments. Finally, it is important to note that function names are considered variables in Python. Thus, they can have new values of any type --- including new functions --- assigned to them on-the-fly.

Below are a few examples of simple functions, called and executed interactively, from the python shell:

>>> def f1(x):
...     print x
...
>>> f1(5)
5
>>> def f2(x)
...     print x*2
...
>>> f2(5)
10
>>> f1                           # note that this only refers to the function
<function f1 at <some address>>  
>>> f1 = f2   
>>> f1(5)                         # you need an argument list to actually invoke it
10

Classes

As in other languages, Python classes allow the bundling of data and methods to operate on the data, providing an easy way to modularize code.

Basic Class Syntax

The basic syntax of a Python class follows:
class <class_name> (<inherit_1>,...,<inherit_n>):
     <body>

A class definition statement creates a class object (different from an instance of a class) called <class_name>. If the list (<inherit_1>,...,<inherit_n>) is provided, then <class_name> inherits from each class, <inherit_1>,...,<inherit_n>, etc. When the class is defined, all the commands in <body> are executed. Any attributes --- variables, function names, etc. --- defined in <body> are are accessible thereafter through the expression:

<class_name>.<attribute_name>

Furthermore, these identifiers can be assigned to at any time; like functions, class definitions can be changed on-the-fly.

Class Instances

To create a class instance, call the class as if it were a function. For example for an already-defined class C, creating an instance named x might involve issuing the command:

x = C()

An instance of a class has copies of all of the attributes present inside the class object of which it is an instance. Attributes of an instance can be accessed through a statement of the form <instance_name>.<attribute_name>. Note that if the value of an attribute is changed in the class object, the change is immediately reflected in all existing class instances. However, changes in a class instance have no effect on the class object. An example of the relationship between class objects and class instances is shown below:

>>> class A :
...    x = 1    # class attribute
...    def show(self) :
...        return "class A's x is " + str(A.x)
...
>>> a = A()
>>> b = A()
>>> print a.show(), b.show()
class A's x is 1 class A's x is 1
>>>
>>> A.x = 15    # change attribute of the class object
>>> print a.show(), b.show()
class A's x is 15 class A's x is 15
>>>
>>> a.x = 20    # this instance attribute created on-the-fly
>>> print a.show(), b.show() + " and a's x is " + str(a.x)
class A's x is 15 class A's x is 15 and a's x is 20

The scoping rules in Python create potential conflicts inside member functions. In particular, the namespaces of a member function and the class of which it is a member are distinct. To distinguish between these two namespaces, the first argument passed to any method provides access to the instance. By convention, programmers use the name self. A simple example is shown below:

>>> class A :
...    x = 1
...    def f(self, val) :
...        self.x = val
...        x = 999
...        print "class's x is " + str(A.x) + \ # backslash escapes carriage return
...              ", instance's x is " + str(self.x) + \
...              ", and function's x is " + str(x)
...
>>> a = A()
>>> a.f(5)
class's x is 1, instance's x is 5, and function's x is 999

Note that a.f is invoked via a.f(5) --- at first glance, the self argument appears to have been neglected! In fact, for methods, Python provides the self value automatically. Also note that in the definition of function f, two different x identifiers are present --- self.x and x --- and these variables remain distinct.

Constructors

Constructors provide a way of automatically initializing the data stored in a class instance upon instantiation. In Python, the user defines a function called __init__ in each class. Whenever the class is instantiated, __init__ is automatically called.

An example of a class with a simple constructor is shown below:

>>> class B:
...     x = 5
...     def __init__(self, y):
...          self.x = y
>>> B.x
5
>>> B(9).x
9

Note that even if x has a value in the class object B, __init__ overrides the value in a particular instance.

Private Methods and Data

In many other object-oriented languages, there is a concept of private data and methods which cannot be accessed from outside the classes' methods. As of version 1.5, Python provides limited support for class-private identifiers via name-mangling. This feature affords some convenience, but ultimately, privacy relies on programmers following expected conventions.

Inheritance

Inheritance allows the creation of a new class which incorporates the data and methods of another and builds upon them. The class which provides the initial collection of methods upon which the new class is based is called the base class. The new class is called the derived class. Also, the derived class and any classes derived from it are subclasses of the original base class. The base class is a superclass of the derived class and any classes derived from it.

In Python the implementation of inheritance is fairly simple. If an attribute is requested from the derived class, but is not present in the derived class, then the request proceeds up to the immediate superclass. If it is still not found there, the request proceeds up to the next superclass in the hierarchy. At the lowest point in the hierarchy where the attribute is found, a value is returned. A simple of example of a base and derived class are shown below:

>>> class Base:
...     x = 5
...
>>> class Derived(Base):
...      y = 6
...
>>> Derived.y
6
>>> Derived.x
5

Note that if a derived class binds a new value to an attribute defined in one of its super-classes, the value in the respective superclass is hidden from view. This behavior is called overriding an attribute of the superclass. Occasionally, however, it is desirable to access superclass attributes, which can be done from inside a derived class by explicitly calling the superclass method through the superclass name. In this case, a reference to self must be manually passed to this function --- it is not passed in automatically. A common use of this technique is to call the __init__ of a classes' base class in order to initialize the base classes' attributes. Python does not call the base class versions of __init__ automatically.

An example of manually calling a base class version of __init__ is given below:

>>> class B:
...     def __init__(self):
...          self.x = 5
...
>>> class D(B):
...     def __init__(self):
...          B.__init__(self) # calling the base class's constructor manually
...          self.y = 6
>>> D().x
5
>>> D().y
6

Miscellaneous Items

Functional Programming Tools

There are three built-in functions that are very useful when used with lists: filter(), map(), and reduce().

filter(function, sequence) returns a sequence (of the same type as sequence, if possible) consisting of those items from sequence for which function(item) is true. For example, to compute some primes:

>>> def f(x): return x % 2 != 0 and x % 3 != 0
>>> filter(f, range(2, 25))
[5, 7, 11, 13, 17, 19, 23]

map(f, sequence) calls f(item) for each of the items in sequence and returns a list for which this function evaluates to True. For example, to compute some cubes:

>>> def cube(x): return x*x*x
>>> map(cube, range(1, 11))
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

More than one sequence may be passed; the function must then have as many arguments as there are sequences and is called with the corresponding item from each sequence (or None if some sequence is shorter than another). For example:

>>> seq = range(8)
>>> def add(x, y): return x+y
...
>>> map(add, seq, seq)
[0, 2, 4, 6, 8, 10, 12, 14]

reduce(f, sequence) returns a single value constructed by calling the two-argument function f on the first two items of the sequence, then on the result and the next item, and so on. For example, to compute the sum of the numbers 1 through 10:

>>> def add(x,y): return x+y
...
>>> reduce(add, range(1, 11))
55

If there's only one item in the sequence, its value is returned; if the sequence is empty, an exception is raised.

A third argument can be passed to indicate the starting value. In this case, the starting value is returned for an empty sequence (no exception is raised). f is then applied to the starting value and the first sequence item, then to the result and the next item, and so on. For example,

>>> def sum(seq):			#DON'T USE THIS
...     def add(x,y): return x+y
...     return reduce(add, seq, 0)
... 
>>> sum(range(1, 11))
55
>>> sum([])
0
Don't use this example's definition of sum! Summing numbers is such a common need that a (faster) built-in function of the same name has already been provided and works exactly like this.

List Comprehensions

List comprehensions provide a concise way to create lists without resorting to use of map(), filter() and/or lambda expressions. (A lambda expression is used to define an anonymous function.) The resulting list definitions tend to be clearer than lists built using those constructs. Each list comprehension consists of an <expression> followed by a for clause, then zero or more for or if clauses. The result will be a list resulting from evaluating the expression in the context of the for and if clauses which follow it. If the expression would evaluate to a tuple, it must be parenthesized.

More formally, the basic format of a list comprehension is:

<expression> for <target> in <iterable> <lc-clauses>

This syntax is treated as an expression and evaluates to a list. For each <target> in <iterable>, <expression> is evaluated and added to the list. <lc-clauses> allows the user to specify further conditions on when <expression> is evaluated and added to the list. <lc-clauses> is a series of zero or more statements of the form:

for <target> in <iterable>

or:

if <test> 

The additional for statement serves as a nested loop which causes <expression> to be evaluated during each iteration through the nested loop as well. Additional if statements place restrictions on the conditions under which the current value of <expression> will be added to the list. <expression> is evaluated and added to the list only if each following <test> evaluates to True.

List comprehensions are best understood through examples. A simple list comprehension which creates a list of items double those in some old list is shown below:

>>> oldlist=range(5)
>>> oldlist
[0, 1, 2, 3, 4]
>>> newlist =[x * 2 for x in oldlist]
>>> newlist
[0, 2, 4, 6, 8]

A more complicated example which allows only odd numbers into the new list is shown below:

>>> oldlist = range(10)
>>> oldlist
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> newlist =[x for x in oldlist if x % 2]
>>> newlist
[1,3,5,7,9]

A similar example below shows the use of multiple if statements to filter out all multiples of 2 and 3:

>>> oldlist = range(10)
>>> oldlist
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> newlist = [x for x in oldlist if x % 2 if x % 3]
>>> newlist
[1, 5, 7]

Finally, the example below shows how to nest additional for-loops inside a list comprehension. Here, it is used to repeat values in a list:

>>> newlist = [x for x in range(5) for y in range(3)]
>>> newlist
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

As mentioned earlier, list comprehensions provide an ideal way to create multidimensional arrays. The code below creates a 5x5 array of zeroes:

>>> newarray = [[0 for col in range(3)] for row in range(5)]
>>> print newarray
[[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
List comprehensions are much more flexible than map() and can be applied to functions with more than one argument and to nested functions:
>>> [str(round(355/113.0, i)) for i in range(1,6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']

File I/O

File objects are considered a built-in type in Python. To create a Python file-object, the built-in function open is used with the following syntax:
<fobj> = open(<filename>, mode='r')

Note that <filename> must be a path to a file and mode must be one of the following values:
Mode Effect
'r' <file> must exist and is opened as read-only
'w' <file> is opened as write-only, overwritten if it does exist, and created if it does not
'a' <file> is opened as write-only; if <file> does not exist, it is created; otherwise, it is appended to
'r+' <file> must exist and is opened for reading and writing
'w+' <file> is opened for reading and writing, created if it doesn't exist, and clobbered if it does
'a+' <file> is opened for reading and writing, created if it does not exist, and appended to if it does

Once file object <fobj> is created, a number of methods are available for interacting with it:
Function Effect
<fobj>.close() closes the file object f
<fobj>.read(size=<num>) reads up to size bytes from <fob> and returns them as a string
<fobj>.readline() reads a single line from <fobj>, \n included, and returns it as a string
<fobj>.readlines() reads and returns every line in <fobj> as strings in a list
<fobj>.write(<str>) writes string <str> to <f>
<fobj>.writelines(<seq>) writes each of the strings in <seq>, one after another

The lines in a file can be iterated over as if they were entries in a sequence. Thus, the following syntax is acceptable:

for <variable> in <fobj>:
     <do something>

A simple example of writing data to a file and then opening that file in order to echo it back is shown below:

>>> outFile = open("testFile.txt", mode='w')
>>> outFile.write("This file gives an example of file I/O!")
>>> outFile.close()
>>> inFile = open("testFile.txt", mode='r')
>>> text = inFile.readline()
>>> print text
This file gives an example of file I/O!

String Formatting

For creating strings, Python provides a syntax similar to C's printf. The basic syntax of a string-formatting expression is below:
<format> % <values>
where <format> is a string containing characters and format specifiers and <values> is a tuple containing the values that are to be replaced via the format specifiers found in the <format> string.

Valid format specifiers and the output they generate are described below:
Specifier Output Format
%d, %i signed decimal integer
%u unsigned decimal integer
%o unsigned octal integer
%x, %X unsigned hexadecimal integers with lowercase and uppercase letters, respectively
%e, %E floating-point value in exponential form with lowercase and uppercase e or E, respectively
%f, %F floating-point value in decimal form
%g, %G acts like %e or %E when the exponent is greater than 4 or less than the precision and like %f or %F otherwise
%c single character
%s string

Output can be further controlled using a number of optional flags, and of which can be placed after the %:
Flag Effect
0 makes the conversion zero-padded
- makes the conversion left-justified
space places a space before a positive number
+ places the numeric sign (+ or -) before any numeric conversion

Following these flags, two other parameters can be specified if desired:
Syntax Effect
any number of digits indicates a minimum width for the conversion
. followed by digits indicates a precisions for a a numerical conversion

Exceptions

An exception is thrown when Python encounters an error. You can catch an error using the try/except syntax as follows:
try:
    <this code might not work>
except:
    <do something if it failed>

If there are no errors, the code works as it normally would, and doesn't execute the except code block. On the other hand, if an error does occur anywhere inside the try block (or in something that is called in the try block), then execution immediately jumps to the except clause.

Optionally, there is an else clause with the try syntax:

try:
    <this code might not work>
except:
    <do something if it failed>
else:
    <do something if it worked>

Try/except syntax is especially useful in cases where failures might occur:

try:
    print robot.x / robot.y
except:
    <gracefully handle failure>
Should print robot.x / robot.y fail for any reason --- perhaps a divide by zero, perhaps robot.x doesn't exist --- the code has an opportunity to recover and continue.

Particular types of errors may also be tested for:

try:
    print robot.x / robot.y
except ZeroDivisionError:
    print "can't divide by zero"
except :
    print "some other problem"

You can also throw your own errors in Python:

if type(x) != type("this") :
   raise TypeError, "x is not a string"

Keyboard Input

If you wish to obtain input from the user via a keyboard, use the input command. For instance:
>>> n = input("enter a number between 1 and 10: ")
enter a number between 1 and 10: 5
>>> n 
5
Used this way, input expects the user to enter an expression that can be successfully evaluated, and literals clearly fulfill this requirement, as do existing variables:
>>> s = input("enter something: ")
enter something: "peanut butter"
>>> print s
peanut butter
>>> t = input("enter something else: ")
enter something else: s
>>> print t
peanut butter

Often, we need to verify that a user's input meets particular criteria, a task that is elegantly solved via Python's exception mechanism. For instance, consider a file foo.py that contains:

def userPickFromSet(prompt, allowableValues) :
    """
    Returns value from keyboard that is one of a specific set of values.
    """
    if prompt != "" :
        prompt += " Choose from " + str(list(allowableValues)) + ": "
    else :
        prompt = "Choose from " + str(list(allowableValues)) + ": "
    tryAgain = True
    msg = prompt
    choice = None
    while tryAgain :
        # loop continues until user enters a valid value
        try :
            choice = input(msg)
            if not choice in allowableValues :
                raise ValueError
        except :
            msg = str(choice) + " was a bad value, try again\n" + prompt
        else :
            tryAgain = False
    return choice

This function could then be used to obtain an integer between 0 and 9:

>>> import foo as U
>>> U.userPickFromSet("enter a value between 0 and 9: ",range(10))
enter a value between 0 and 9:  Choose from [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: -1
-1 was a bad value, try again!
enter a value between 0 and 9:  Choose from [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: 11
11 was a bad value, try again!
enter a value between 0 and 9:  Choose from [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: 4
4

Note also our that Python's docstring functionality can be used here:

>>> help(U.userPickFromSet)
because we followed the function's header by an informative piece of text:
userPickFromSet(prompt, allowableValues)
    Returns value from keyboard that is one of a specific set of values.
Similar help functionality for classes is also available provided a comment follows the class' header.

Argument Lists and Dictionaries

When passing arguments to functions wherein their name and/or number can vary, use the *args and **keywords special forms:
  • *args refers to all of the rest of the (non-keyword-based) arguments
  • **kwargs refers to any remaining keyword-based arguments

For example:

>>> def func1(*args, **kwargs):
...     print args
...     print kwargs
... 
>>> func1(1, 2, 3, d_item1 = "hello", d_item2 = "world", name = "testing")
(1, 2, 3)
{'d_item1': 'hello', 'name': 'testing', 'd_item2': 'world'}

These keywords are handy when writing functions that wrap around other functions, so that you don't know in advance how it will be used:

>>> def func1(*args, **kwargs):
...     return func2(*args, **kwargs)

Notice that * and ** can be used in the sending and receiving of parameters.

Further Reading

  1. Downey, A., Elkner, J., Meyers, C. How to Think Like a Computer Scientist.  ibiblio.org/obp/thinkCS/python/english/.
  2. Python Tutorial.  docs.python.org/tut/tut.html
  3. Python Language Website.  www.python.org/

Up: PyroModulesContents


Home ]Software ]Curriculum ]Hardware ]Community ]News ]Publications ]Search ]

CreativeCommons View Wiki Source | Edit Wiki Source | Mail Webmaster