Section 3.6. First Python Programs


3.6. First Python Programs

Now that we are familiar with the syntax, style, variable assignment, and memory allocation, it is time to look at slightly more complex code. You may or may not be familiar with all of the constructs of Python that we're going to show, but we believe that Python is so simple and elegant that you should be able to figure out what each piece of code does.

We are going to introduce two related scripts that manipulate text files. The first, makeTextFile.py, creates text files. It prompts the user for each line of text and writes the results to a file. The other, readTextFile.py, reads and displays the contents of a text file to the screen.

Take a look at both now, and see if you can figure out how each works.

Example 3.1. File Create (makeTextFile.py)

This application prompts the user for a (nonexistent) filename, then has the user enter each line of that file (one at a time). Finally, it writes the entire text file to disk.

1  #!/usr/bin/env python 2 3  'makeTextFile.py -- create text file' 4 5  import os 6  ls = os.linesep 7 8  # get filename 9  while True: 10 11     if os.path.exists(fname): 12        print "ERROR: '%s' already exists" % fname 13     else: 14        break 15 16 # get file content (text) lines 17 all = [] 18 print "\nEnter lines ('.' by itself to quit).\n" 19 20 # loop until user terminates input 21 while True: 22     entry = raw_input('> ') 23     if entry == '.': 24         break 25     else: 26         all.append(entry) 27 28 # write lines to file with proper line-ending 29 fobj = open(fname, 'w') 30 fobj.writelines(['%s%s' % (x, ls) for x in all]) 31 fobj.close() 32 print 'DONE!'

Lines 13

The Unix startup line is followed by the module documentation string. Keep your documentation string simple yet descriptive enough to be useful. Ours is a bit short, but so is this script. (We invite the reader to take a look at the documentation string at the commencement of the cgi module in the standard library for a seriously lengthy example of module documentation.)

Lines 56

We import the operating system (os) module next, and in line 6, we create a new local alias for the linesep attribute of that module. By doing this, we can shorten the name of the variable and also speed up access to it.

Core Tip: Use local variables to substitute for module attributes

Names like os.linesep require the interpreter to do two lookups: (1) lookup os to find that it is a module, and (2) look up the linesep attribute of that module. Because modules are also global variables, we pay another penalty. If you use an attribute like this often in a function, we recommend you alias it to a single local variable. Lookups are much fasterlocal variables are always searched first before globals, and we don't have attribute lookups either. This is one of the tricks in making your programs faster: replace often-used (and name-lengthy) module attributes with local references. Your code runs faster and has less clutter with a shorter name.

In our code snippet, we do not have a function to show you an example of using a local alias. Instead, we have a global alias, which is halfway there. At least we do not have to perform two lookups to get to the object.


Lines 814

If it is not apparent already, this is an "infinite loop," meaning we are presented with a body of code that will repeat and run forever unless we exit the looplook for a break statement somewhere! The while true conditional causes this to happen because while statements execute whenever its conditional expression evaluates to Boolean true, and true is Boolean true.

Lines 1014 prompt the user for an unused filename, meaning that the filename entered should not be the name of an already existing file. The raw_input() built-in function takes an argument to use as the prompt to the user. The resulting string entered by the user is the return value of raw_input(), which in this case gets assigned to fname.

If the user is unlucky enough to pick a name already in use, we notify the user and return the user to the prompt to enter another (file)name. Note that os.path.exists() is a helper function in the os.path (sub)module, which helps us make this determination. Only when a file with such a name does not exist, meaning that os.path.exists() returns False, do we break out of this loop and continue.

Lines 1626

This is the part of our application that gives the user some instruction and prompts them for the contents of our text file, one line at a time. The all list will hold each linewe initialize it on line 17. Line 21 begins another infinite loop, which prompts the user for each line of the text file and only terminates when they enter a period '.' on a line by itself. The if-else statement on lines 2326 look for that sentinel and break out of the loop if it is seen (line 24); otherwise it adds another line to our total (line 26).

Lines 2832

Now that we have the entire contents in memory, we need to dump it to the text file. Line 29 opens the file for write, and line 30 writes each line to the file. Every file requires a line terminator (or termination character[s]). The construct on line 30, called a list comprehension, does the following: for every line in our file, append it with the appropriate line terminator for our platform. '%s%s' puts a line next to the termination character(s), and the grouping (x, ls) represents each line x of all lines and the terminatorfor Unix, it is '\n', DOS and Win32, '\r\n', etc. By using os.linesep, we do not need to have code to check which operating system this program is running on in order to determine which line terminating character(s) to use.

The file object's writelines() method then takes the resulting list of lines (now with terminators) and writes it to the file. The file is then closed in line 31, and we are done!

Not too bad, right? Now let us look at how to view the file we just created! For this, we have your second Python program, readTextFile.py. As you will see, it is much shorter than makeTextfile.py. The complexity of file creation is almost always greater than the reading of it. The only new and interesting part for you is the appearance of an exception handler.

Lines 13

These are the Unix startup line and module documentation string as usual.

Lines 57

Unlike makeTextFile.py where we kept pegging the user for names until they he or she chooses an unused filename, we don't care in this example.

Example 3.2. File Read and Display (readTextFile.py)

1  #!/usr/bin/env python 2 3  'readTextFile.py -- read and display text file' 4 5  # get filename 6  fname = raw_input('Enter filename: ') 7  print 8 9  # attempt to open file for reading 10 try: 11     fobj = open(fname, 'r') 12 except IOError, e: 13     print "*** file open error:", e 14 else: 15     # display contents to the screen 16     for eachLine in fobj: 17         print eachLine, 18     fobj.close()

In other words, we are performing the validation elsewhere (if at all). Line 7 just displays a new line to separate the prompting of the filename and the contents of the file.

Lines 918

This next Python construct (other than the comment) represents the rest of the script. This is a try-except-else statement. The try clause is a block of code that we want to monitor for errors. In our code (lines 1011), we are attempting to open the file with the name the user entered.

The except clause is where we decide what type of errors we're looking out for and what to do if such errors occur. In this case (lines 1213), we are checking to see if the file open() failedthis is usually an IOError type of error.

Finally, lines 1418 represent the else clause of a try-exceptthe code that is executed if no errors occurred in the TRy block. In our case, we display each line of the file to the screen. Note that because we are not removing the trailing whitespace (line termination) characters from each line, we have to suppress the NEWLINE that the print statement automatically generatesthis is done by adding a trailing comma to the end of the print statement. We then close the file (line 18), which ends the program.

One final note regarding the use of os.path.exists() and an exception handler: The author is generally in favor of the former, when there is an existing function that can be used to detect error conditionsand even more simply, where the function is Boolean and gives you a "yes" or "no" answer. (Note that there is probably already an exception handler in such a function.) Why do you have to reinvent the wheel when there's already code just for that purpose?

An exception handler is best applied when there isn't such a convenient function, where you the programmer must recognize an "out of the ordinary" error condition and respond appropriately. In our case, we were able to dodge an exception because we check to see if a file exists, but there are many other situations that may cause a file open to fail, such as improper permissions, the connection to a network drive is out, etc. For safety's sake, you may end up with "checker" functions like os.path.exists() in addition to an exception handler, which may be able to take care of a situation where no such function is available.

You will find more examples of file system functions in Chapter 9 and more about exception handling in Chapter 10.



Core Python Programming
Core Python Programming (2nd Edition)
ISBN: 0132269937
EAN: 2147483647
Year: 2004
Pages: 334
Authors: Wesley J Chun

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net