Python 101 - Introduction to Python - Part 2

by Dave Kuhlman
Rexx.com
Wednesday, 3rd August 2005

Control Structures

if 

The if statement enables us to execute code (or not) depending on a condition.

 

  • "if condition: ..."

     

  • "if condition: ... else: ..."

     

  • "if condition1: ... elif condition2: ... else: ..."

     

Here is an example:

 

>>> y = 25
>>>
>>> if y > 15:
... print 'y is large'
... else:
... print 'y is small'
...
y is large
A few notes:

 

  • The condition can be any expression, i.e. something that returns a value. A detailed description of expressions can be found at http://www.python.org/doc/current/ref/expressions.html.

     

  • Parentheses are not needed around the condition. Use parentheses to group sub-expressions and control order of evaluation when the natural operator precedence is not what you want. Python's operator precedences are described at http://www.python.org/doc/current/ref/summary.html.

     

  • Python has no switch statement. Use if-elif. Or consider using a dictionary, for example:

     

    def function1():
        print "Hi. I'm function1."
        def function2():
        print "Hi. I'm function2."
        def function3():
        print "Hi. I'm function3."
       
        mapper = {'one': function1, 'two': function2, 'three': function3}
       
        while 1:
        code = raw_input('Enter "one", "two", "three", or "quit": ')
        if code == 'quit':
        break
        if code not in mapper:
        continue
        mapper[code]()

Here is an example:

 

>>> collection = [111,222,333]
>>> for item in collection:
... print 'item:', item
...
item: 111
item: 222
item: 333

Comments:

 

  • You can iterate over strings, lists, and tuples.

     

  • Iterate over the keys or values in a dictionary with "aDict.keys()" and "aDict.values()". Here is an example:

     

    >>> aDict = {'cat': 'furry and cute', 'dog': 'friendly and smart'}
        >>> aDict.keys()
        ['dog', 'cat']
        >>> aDict.values()
        ['friendly and smart', 'furry and cute']
        >>> for key in aDict.keys():
        ... print 'A %s is %s.' % (key, aDict[key])
        ...
        A dog is friendly and smart.
        A cat is furry and cute.

     

  • In recent versions of Python, a dictionary itself is an iterator for its keys. Therefore, you can also do the following:

     

    >>> for key in aDict:
        ... print 'A %s is %s.' % (key, aDict[key])
        ...
        A dog is friendly and smart.
        A cat is furry and cute.

     

  • And, in recent versions of Python, a file is also an iterator over the lines in the file. Therefore, you can do the following:

     

    >>> infile = file('tmp.txt', 'r')
        >>> for line in infile:
        ... print line,
        ...
        This is line #1
        This is line #2
        This is line #3
        >>> infile.close()

     

  • There are other kinds of iterations. For example, the built-in iter will produce an iterator from a collection. Here is an example:

     

    >>> anIter = iter([11,22,33])
        >>> for item in anIter:
        ... print 'item:', item
        ...
        item: 11
        item: 22
        item: 33

     

  • You can also implement iterators of your own. To do so, define a function that returns values with yield (instead of with return). Here is an example:

     

    >>> def t(collection):
        ... icollection = iter(collection)
        ... for item in icollection:
        ... yield '||%s||' % item
        ...
        >>> for x in t(collection): print x
        ...
        ||111||
        ||222||
        ||333||

while

while is another repeating statement. It executes a block of code until a condition is false.

Here is an example:

 

>>> reply = 'repeat'
>>> while reply == 'repeat':
... print 'Hello'
... reply = raw_input('Enter "repeat" to do it again: ')
...
Hello
Enter "repeat" to do it again: repeat
Hello
Enter "repeat" to do it again: bye

Comments:

 

  • Use the break statement to exit from a loop. This works for both for and while. Here is an example that uses break in a for statement:

     

    # for_break.py
        """Count lines until a line that begins with a double #.
        """
       
        import sys
       
        def countLines(infilename):
        infile = file(infilename, 'r')
        count = 0
        for line in infile.readlines():
        line = line.strip()
        if line[:2] == '##':
        break
        count += 1
        return count
       
        def usage():
        print 'Usage: python python_101_for_break.py <infilename>'
        sys.exit(-1)
       
        def main():
        args = sys.argv[1:]
        if len(args) != 1:
        usage()
        count = countLines(args[0])
        print 'count:', count
       
        if __name__ == '__main__':
        main()

     

  • Use the continue statement to skip the remainder of the code block in a for or while. A continue is a short-circuit which, in effect, branches back to the top of the for or while (or if you prefer, to the end of the block).

     

  • The test "if __name__ == '__main__':" is used to enable the script to both be (1) imported and (2) run from the command line. That condition is true only when the script is run, but not imported. This is a common Python idiom, which you should consider including at the end of your scripts, whether (1) to give your users a demonstration of what your script does and how to use it or (2) to provide a test of the script.

try-except and raise -- Exceptions

Use a try:except: block to catch an exception.

Use raise to raise an exception.

Comments and hints:

 

  • Catch all exceptions with a "bare" except:. For example:

     

    >>> try:
        ... x = y
        ... except:
        ... print 'y not defined'
        ...
        y not defined

     

  • Catch a specific error by refering to an exception class in the except:. To determine what error or exception you want to catch, generate it and try it. Because Python reports errors with a walk-back that ends with reporting the exception, you can learn which exception to catch. For example, suppose I want to learn which exception is thrown when a Python can't open a file. I can try the following from the interactive prompt:

     

    >>> myfile = file('amissingfile.py', 'r')
        Traceback (most recent call last):
        File "<stdin>", line 1, in ?
        IOError: [Errno 2] No such file or directory: 'amissingfile.py'

    So, now I know that I can do:

     

    >>> try:
        ... myfile = file('amissingfile.py', 'r')
        ... except IOError:
        ... print 'amissingfile.py is missing'
        ...
        amissingfile.py is missing

     

  • You can customize your error handling still further by passing an object on the raise and catching that object in the except:. By doing so, you can pass information up from the raise statement to an exception handler. One way of doing this is to pass an object. A reasonable strategy is to define a sub-class of a standard exception. For example:

     

    >>> class E(RuntimeError):
        ... def __init__(self, msg):
        ... self.msg = msg
        ... def getMsg(self):
        ... return self.msg
        ...
        >>>
        >>> try:
        ... raise E('my test error')
        ... except E, obj:
        ... print 'Msg:', obj.getMsg()
        ...
        Msg: my test error

Reading Text Files

To read a text file, first create a file object. Here is an example:

 

inFile = file('messages.log', 'r')

Then use one or more of the file object's methods to process the contents of the file. Here are a few strategies:

 

  • Use "inFile.read()" to get the entire contents of the file (a string). Example:

     

    >>> inFile = file('tmp.txt', 'r')
        >>> content = inFile.read()
        >>> inFile.close()
        >>> print content
        aaa bbb ccc
        ddd eee fff
        ggg hhh iii
       
        >>> words = content.split()
        >>> print words
        ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff', 'ggg', 'hhh', 'iii']
        >>> for word in words:
        ... print word
        ...
        aaa
        bbb
        ccc
        ddd
        eee
        fff
        ggg
        hhh
        iii

     

  • Use "for line in inFile:" to process one line at a time. You can do this because (at least since Python 2.3) file objects obey the iterator protocol, that is they support methods __iter__ and next. For more on the iterator protocol see http://www.python.org/doc/current/lib/typeiter.html.

    Example:

     

    >>> inFile = file('tmp.txt', 'r')
        >>> for line in inFile:
        ... print 'Line:', line,
        ...
        Line: aaaaa
        Line: bbbbb
        Line: ccccc
        Line: ddddd
        Line: eeeee
        >>> inFile.close()

     

  • For earlier versions of Python, use "inFile.readlines()" or "inFile.xreadlines()".

     

  • If your want to get the contents of an entire text file as a collection of lines, use readlines. Example:

     

    >>> inFile = file('tmp.txt', 'r')
        >>> lines = inFile.readlines()
        >>> print lines
        ['aaaaa\n', 'bbbbb\n', 'ccccc\n', 'ddddd\n', 'eeeee\n']
        >>> print lines[2]
        ccccc
       
        >>> inFile.close()

Iterator objects

This section explains how to implement iterator objects, that is a class that obeys the iterator protocol.

We explain generators first -- A generator is a function which uses yield. Because it returns values with yield instead of with return, the function can be resumed immediately after the yield. Here is an example:

 

def generateItems(seq):
for item in seq:
yield 'item: %s' % item

anIter = generateItems([])
print 'dir(anIter):', dir(anIter)
anIter = generateItems([111,222,333])
for x in anIter:
print x
anIter = generateItems(['aaa', 'bbb', 'ccc'])
print anIter.next()
print anIter.next()
print anIter.next()
print anIter.next()

Running this example produces the following output:

 

dir(anIter): ['__class__', '__delattr__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__iter__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__str__', 'gi_frame',
'gi_running', 'next']
item: 111
item: 222
item: 333
item: aaa
item: bbb
item: ccc
Traceback (most recent call last):
File "iterator_generator.py", line 14, in ?
print anIter.next()
StopIteration

Notes:

 

  • Notice that the value returned by the call to the generator (function) is an iterator. It obeys the iterator protocol. That is, "dir(anIter)" shows that it has both __iter__ and next.

     

  • Because it is an iterator, we can use a for statement to iterate over the values returned by the generator.

     

  • We can also get its values by repeatedly calling the next method, until it raises the StopIteration exception. This ability to call the next method enables us to pass the iterator object around and get values at different locations in our code.

     

  • Once we have obtained all the values from an iterator, it is, in effect, "empty". The iterator protocol, in fact, specifies that once an iterator raises the StopIteration exception, it should continue to do so. Another way to say this, is that there is no "rewind" operation. But, you can call the the generator function again to get a "fresh" iterator.

     

Now, we will implement a class that obeys the iterator protocol. By doing so, we can produce "iterable" objects. Here is an example:

 

class IteratorExample:
def __init__(self, s):
self.s = s
self.next = self._next().next
self.exhausted = 0
def _next(self):
if not self.exhausted:
flag = 0
for x in self.s:
if flag:
flag = 0
yield x
else:
flag = 1
self.exhausted = 1
def __iter__(self):
return self._next()

def main():
a = IteratorExample('edcba')
for x in a:
print x
print '=' * 30
a = IteratorExample('abcde')
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()

if __name__ == '__main__':
main()

Iterating over an instance of the above class produces every other object from the sequence with which the instance was constructed. Running the above example produces the following:

 

d
b
==============================
b
d
Traceback (most recent call last):
File "iterator_class.py", line 24, in ?
print a.next()
StopIteration

Explanation:

 

  • Method __iter__ should return an iterator. So, in our example it calls method _next to produce that iterator. _next is a generator (it contains yield), which means that it returns an iterator.

     

  • Method next should return the next item in the sequence. But, this is exactly what the next method of the iterator returned by _next does. So, we just capture that using "self.next = self._next().next".

     

The definition of the iterator protocol is at http://www.python.org/doc/current/lib/typeiter.html.

Continue reading Part 3 of Python 101 - Introduction to Python


Options:
Printer Friendly
Email Friend

About The Author:

Dave Kuhlman has worked for many years on a variety of software development projects, in several programming languages, and on more than one platform. Because of Python's clear syntax, developer friendliness, and broad utility, Dave focuses his energy on the Python language, on systems built with Python, and on developing documentation and training materials for those systems. Dave's current work involves XML processing in Python as well as the development of tools and documentation for Zope and the CMSs (content management systems) that run on top of Zope, Dave's current platform is Debian GNU/Linux; he has installed and administers a small network composed of several Linux boxes behind a Linux router/gateway. More information about Dave's work can be found at http://www.rexx.com/~dkuhlman.

Developer Categories



Developer Tutorials
ASP
CGI & Perl
CSS
Flash
HTML
Java
JavaScript
MySQL
PHP
Python
XML

Developer Documentation

Developer Tools



Search our Developer Tutorials
  The DevSyndicate Network