Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Beginning Python (2005)

.pdf
Скачиваний:
158
Добавлен:
17.08.2013
Размер:
15.78 Mб
Скачать

Building a Module

You must import a module prior to calling the help function to read the modules documentation.

The help function first prints the documentation for the module:

Help on module meal:

NAME

meal - Module for making meals in Python.

FILE

/Users/ericfj/writing/python/meal.py

DESCRIPTION

Import this module and then call makeBreakfast(), makeDinner() or makeLunch().

Note how the help function separates the first summary line of the module documentation from the rest of the documentation. The following shows the original string that documents this module:

“””

Module for making meals in Python.

Import this module and then call makeBreakfast(), makeDinner() or makeLunch().

“””

The help function pulls out the first line for the NAME section of the documentation and the rest for the

DESCRIPTION section.

The help function summarizes the classes next and then shows the documentation for each class:

CLASSES exceptions.Exception

AngryChefException SensitiveArtistException

Meal

Breakfast

Dinner

Lunch

Each class is shown indented based on inheritance. In this example, the summary shows that the Breakfast class inherits from the Meal class.

For each function and method, the help function prints out the documentation:

| printIt(self, prefix=’’)

|Print the data nicely.

However, if you just have comments near a function or method definition, the help function will try to associate a comment with the function or method. This doesn’t always work, however, as the help function alphabetizes the methods and functions. For example:

161

TEAM LinG

Chapter 10

|

 

|

setDrink(self, drink=’coffee’)

|

# Setter for the name.

|

 

|

setFood(self, food=’omelet’)

|

# Setter for the drink.

|

 

|setName(self, name=’’)

|# Setter for the name.

Note how the comments are associated with the wrong methods. Here is the original code:

# Setter for the food.

def setFood(self, food=’omelet’): self.food = food

# Setter for the drink.

def setDrink(self, drink=’coffee’): self.drink = drink

# Setter for the name.

def setName(self, name=’’): self.name = name

The lesson here is to follow the Python conventions for documenting methods. To fix this error, change the comments that appear above each method into a Python documentation string. Move the Python documentation string down to the line immediately following the corresponding def command.

As you develop your module, you can call the help function repeatedly to see how changes in the code change the documentation. If you have changed the Python source file for your module, however, you need to reload the module prior to calling help. The reload function takes a module, as does help. The syntax follows:

reload(module)

help(module)

For example, to reload the module meal, use the following code:

>>> reload(meal)

<module ‘meal’ from ‘meal.py’>

Just as documentation is important, so is testing. The more you can test your modules, the better your modules will fit into Python applications. You’ll know that the functionality of the modules works prior to using those modules in a program.

Testing Your Module

Testing is hard. Testing is yucky. That’s why testing is often skipped. Even so, testing your module can verify that it works. More important, creating tests enables you to make changes to your module and then verify that the functionality still works.

162

TEAM LinG

Building a Module

Any self-respecting module should include a test function that exercises the functionality in the module. Your tests should create instances of the classes defined in the module, and call methods on those instances.

For example, the following method provides a test of the meal module:

def test():

‘’’Test function.’’’

print ‘Module meal test.’

# Generic no arguments. print ‘Testing Meal class.’ m = Meal()

m.printIt(“\t”)

m = Meal(‘green eggs and ham’, ‘tea’) m.printIt(“\t”)

# Test breakfast

print ‘Testing Breakfast class.’ b = Breakfast()

b.printIt(“\t”)

b.setName(‘breaking of the fast’) b.printIt(“\t”)

# Test dinner

print ‘Testing Dinner class.’ d = Dinner()

d.printIt(“\t”)

# Test lunch

print ‘Testing Lunch class.’ l = Lunch()

l.printIt(“\t”)

print ‘Calling Lunch.setFood().’ try:

l.setFood(‘hotdog’) except AngryChefException:

print “\t”,’The chef is angry. Pick an omelet.’

Make your test functions part of your modules, so the tests are always available. You’ll learn more about testing in Python in Chapter 12.

Testing is never done. You can always add more tests. Just do what you can.

163

TEAM LinG

Chapter 10

Running a Module as a Program

Normally, modules aren’t intended to be run on their own. Instead, other Python scripts import items from a module and then use those items. However, because a module can be any file of Python code, you can indeed run a module.

Because modules aren’t meant to be run on their own, Python defines a convention for modules. When a module is run on its own, it should execute the module tests. This provides a simple means to test your modules: Just run the module as a Python script.

To help with this convention, Python provides a handy idiom to detect whether your module is run as a program. Using the test function shown previously, you can use the following code to execute your module tests:

if __name__ == ‘__main__’:

test()

If you look at the source code for the standard Python modules, you’ll find this idiom used repeatedly.

The next example runs the meal module, created in the section “Creating a Whole Module.”

Try It Out

Running a Module

You can run a module, such as the meal module, as a program by using a command like the following:

$ python meal.py Module meal test. Testing Meal class.

A fine generic meal with omelet and coffee

A fine generic meal with green eggs and ham and tea Testing Breakfast class.

A fine breakfast with omelet and coffee

A fine breaking of the fast with omelet and coffee

Testing Dinner class.

A gourmet dinner with steak and merlot

Testing Lunch class.

A fine midday meal with sandwich and gin and tonic

Calling Lunch.setFood().

The chef is angry. Pick an omelet.

How It Works

This example runs a module as a Python program. Using the idiom to detect this situation, the module merely runs the test function. The output you see is the output of the tests.

Note how the output runs an instance of each class defined in the module, as well as tests the raising of the AngryChefException.

If you follow all of the guidelines in this section, your modules will meet the expectations of other Python developers. Moreover, your modules will work better in your scripts. You can see all of this in action in the next section, which shows a complete Python module.

164

TEAM LinG

Building a Module

Creating a Whole Module

The sections in this chapter so far show the elements you need to include in the modules you create. The following example shows a complete module using the techniques described so far.

The meal module doesn’t do much. It supposedly modules a domain that includes food and drink over three daily meals.

Obviously, this module doesn’t support Hobbits who require more than three meals a day.

The code in this module is purposely short. The intent is not to perform a useful task but instead to show how to put together a module.

Try It Out

Finishing a Module

Enter the following code and name the file meal.py:

“””

Module for making meals in Python.

Import this module and then call makeBreakfast(), makeDinner() or makeLunch().

“””

__all__ = [‘Meal’,’AngryChefException’, ‘makeBreakfast’, ‘makeLunch’, ‘makeDinner’, ‘Breakfast’, ‘Lunch’, ‘Dinner’]

# Helper functions.

def makeBreakfast():

‘’’ Creates a Breakfast object.’’’

return Breakfast()

def makeLunch():

‘’’ Creates a Breakfast object.’’’ return Lunch()

def makeDinner():

‘’’ Creates a Breakfast object.’’’ return Dinner()

# Exception classes.

class SensitiveArtistException(Exception): ‘’’Exception raised by an overly-sensitive artist.

Base class for artistic types.’’’ pass

165

TEAM LinG

Chapter 10

class AngryChefException(SensitiveArtistException): ‘’’Exception that indicates the chef is unhappy.’’’ pass

class Meal:

‘’’Holds the food and drink used in a meal. In true object-oriented tradition, this class

includes setter methods for the food and drink.

Call printIt to pretty-print the values. ‘’’

def __init__(self, food=’omelet’, drink=’coffee’): ‘’’Initialize to default values.’’’

self.name = ‘generic meal’ self.food = food self.drink = drink

def printIt(self, prefix=’’): ‘’’Print the data nicely.’’’

print prefix,’A fine’,self.name,’with’,self.food,’and’,self.drink

# Setter for the food.

def setFood(self, food=’omelet’): self.food = food

# Setter for the drink.

def setDrink(self, drink=’coffee’): self.drink = drink

# Setter for the name.

def setName(self, name=’’): self.name = name

class Breakfast(Meal):

‘’’Holds the food and drink for breakfast.’’’

def __init__(self):

‘’’Initialize with an omelet and coffee.’’’ Meal.__init__(self, ‘omelet’, ‘coffee’) self.setName(‘breakfast’)

class Lunch(Meal):

‘’’Holds the food and drink for lunch.’’’

def __init__(self):

‘’’Initialize with a sandwich and a gin and tonic.’’’ Meal.__init__(self, ‘sandwich’, ‘gin and tonic’) self.setName(‘midday meal’)

166

TEAM LinG

Building a Module

# Override setFood().

def setFood(self, food=’sandwich’):

if food != ‘sandwich’ and food != ‘omelet’: raise AngryChefException

Meal.setFood(self, food)

class Dinner(Meal):

‘’’Holds the food and drink for dinner.’’’

def __init__(self):

‘’’Initialize with steak and merlot.’’’ Meal.__init__(self, ‘steak’, ‘merlot’) self.setName(‘dinner’)

def printIt(self, prefix=’’): ‘’’Print even more nicely.’’’

print prefix,’A gourmet’,self.name,’with’,self.food,’and’,self.drink

def test():

‘’’Test function.’’’

print ‘Module meal test.’

# Generic no arguments. print ‘Testing Meal class.’ m = Meal()

m.printIt(“\t”)

m = Meal(‘green eggs and ham’, ‘tea’) m.printIt(“\t”)

# Test breakfast

print ‘Testing Breakfast class.’ b = Breakfast()

b.printIt(“\t”)

b.setName(‘breaking of the fast’) b.printIt(“\t”)

# Test dinner

print ‘Testing Dinner class.’ d = Dinner()

d.printIt(“\t”)

# Test lunch

print ‘Testing Lunch class.’ l = Lunch()

l.printIt(“\t”)

167

TEAM LinG

Chapter 10

print ‘Calling Lunch.setFood().’ try:

l.setFood(‘hotdog’) except AngryChefException:

print “\t”,’The chef is angry. Pick an omelet.’

# Run test if this module is run as a program. if __name__ == ‘__main__’:

test()

How It Works

The meal module follows the techniques shown in this chapter for creating a complete module, with testing, documentation, exceptions, classes, and functions. Note how the tests are about as long as the rest of the code. You’ll commonly find this to be the case.

After you’ve built a module, you can import the module into other Python scripts. For example, the following script calls on classes and functions in the meal module:

import meal

print ‘Making a Breakfast’ breakfast = meal.makeBreakfast()

breakfast.printIt(“\t”)

print ‘Making a Lunch’ lunch = meal.makeLunch()

try:

lunch.setFood(‘pancakes’) except meal.AngryChefException:

print “\t”,’Cannot make a lunch of pancakes.’ print “\t”,’The chef is angry. Pick an omelet.’

This example uses the normal form for importing a module:

import meal

When you run this script, you’ll see output like the following:

$ python mealtest.py

Making a Breakfast

A fine breakfast with omelet and coffee

Making a Lunch

Cannot make a lunch of pancakes.

The chef is angry. Pick an omelet.

The next script shows an alternate means to import the module:

from meal import *

168

TEAM LinG

Building a Module

The full script follows:

from meal import *

print ‘Making a Breakfast’ breakfast = makeBreakfast()

breakfast.printIt(“\t”)

print ‘Making a Lunch’ lunch = makeLunch()

try:

lunch.setFood(‘pancakes’) except AngryChefException:

print “\t”,’Cannot make a lunch of pancakes.’ print “\t”,’The chef is angry. Pick an omelet.’

Note how with this import form, you can call the makeLunch and makeBreakfast functions without using the module name, meal, as a prefix on the call.

The output of this script should look familiar.

$ python mealtest2.py

Making a Breakfast

A fine breakfast with omelet and coffee

Making a Lunch

Cannot make a lunch of pancakes.

The chef is angry. Pick an omelet.

Be very careful with the names you use for variables. The example module has a name of meal. This means you don’t want to use that name in any other context, such as for a variable. If you do, you will effectively overwrite the definition of meal as a module. The following example shows the pitfall to this approach.

Try It Out

Smashing Imports

Enter the following script and name the file mealproblem.py:

import meal

print ‘Making a Breakfast’ meal = meal.makeBreakfast()

meal.printIt(“\t”)

print ‘Making a Lunch’ lunch = meal.makeLunch()

169

TEAM LinG

Chapter 10

try:

lunch.setFood(‘pancakes’) except meal.AngryChefException:

print “\t”,’Cannot make a lunch of pancakes.’ print “\t”,’The chef is angry. Pick an omelet.’

When you run this script, you’ll see the following error:

$ python mealproblem.py

Making a Breakfast

A fine breakfast with omelet and coffee Making a Lunch

Traceback (most recent call last): File “mealproblem.py”, line 10, in ?

lunch = meal.makeLunch()

AttributeError: Breakfast instance has no attribute ‘makeLunch’

How It Works

This script uses meal as a module as well as meal as an instance of the class Breakfast. The following lines are the culprit:

import meal

meal = meal.makeBreakfast()

When you run this code, the name meal is now a variable, an instance of the class Breakfast. This changes the interpretation of the following line:

lunch = meal.makeLunch()

The intent of this line is to call the function makeLunch in the module meal. However, because meal is now an object, the Python interpreter tries to call the makeLunch method on the object, an instance of the Breakfast class. Because the Breakfast class has no method named makeLunch, the Python interpreter raises an error.

The syntax for using modules and calling functions in modules looks very much like the syntax for calling methods on an object. Be careful.

After building your module and testing it, the next step is to install it.

Installing Your Modules

The Python interpreter looks for modules in the directories listed in the sys.path variable. The sys.path variable includes the current directory, so you can always use modules available locally. If you want to use a module you’ve written in multiple scripts, or on multiple systems, however, you need to install it into one of the directories listed in the sys.path variable.

170

TEAM LinG