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

Beginning Python (2005)

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

Answers to Exercises

If you called this from within another function, the stack would be one layer deeper, and you would see the information relating to that extra layer as well.

Chapter 6

Exercise 1 solution

def mix(self, display_progress = True): “””

mix(display_progress = True) - Once the ingredients have been obtained from a fridge call this

to prepare the ingredients. If display_progress is False do not print messages.

“””

for ingredient in self.from_fridge.keys(): if display_progress == True:

print “Mixing %d %s for the %s omelet” % (self.from_fridge[ingredient], ingredient, self.kind)

self.mixed = True

Exercise 2 solution

Note that you could go one step further and make the quiet setting of the mix function an option, too. As it is, this doesn’t give you much feedback about what’s going on, so when you test it, it may look a bit strange.

def quick_cook(self, fridge, kind = “cheese”, quantity = 1): “””

quick_cook(fridge, kind = “cheese”, quantity = 1) -

performs all the cooking steps needed. Turns out an omelet fast.

“””

self.set_kind(kind) self.get_ingredients(fridge) self.mix(False)

self.make()

Exercise 3 solution

Just the documentation, not the functions, would look something like this. However, you should find a format that suits you.

Note that only undocumented functions will have their docstrings described here.

class Omelet:

“””This class creates an omelet object. An omelet can be in one of two states: ingredients, or cooked.

An omelet object has the following interfaces: get_kind() - returns a string with the type of omelet set_kind(kind) - sets the omelet to be the type named

set_new_kind(kind, ingredients) - lets you create an omelet

mix() - gets called after all the ingredients are gathered from the fridge

581

TEAM LinG

Appendix A

cook() - cooks the omelet “””

def __init__(self, kind=”cheese”): “””__init__(self, kind=”cheese”)

This initializes the Omelet class to default to a cheese omelet. Other methods

“”” self.set_kind(kind) return

def set_kind(self, kind): “””

set_kind(self, kind) - changes the kind of omelet that will be created if the type of omelet requested is not known then return False

“””

def get_kind(self): “””

get_kind() - returns the kind of omelet that this object is making “””

def set_kind(self, kind): “””

set_kind(self, kind) - changes the kind of omelet that will be created if the type of omelet requested is not known then return False

“””

def set_new_kind(self, name, ingredients): “””

set_new_kind(name, ingredients) - create a new type of omelet that is called “name” and that has the ingredients listed in “ingredients”

“””

def __known_kinds(self, kind): “””

__known_kinds(kind) - checks for the ingredients of “kind” and returns them returns False if the omelet is unknown.

“””

def get_ingredients(self, fridge): “””

get_ingredients(fridge) - takes food out of the fridge provided “””

def mix(self): “””

mix() - Once the ingredients have been obtained from a fridge call this to prepare the ingredients.

“””

def make(self): “””

make() - once the ingredients are mixed, this cooks them “””

582

TEAM LinG

Answers to Exercises

Exercise 4 solution

>>> print “%s” % o.__doc__

This class creates an omelet object. An omelet can be in one of two states: ingredients, or cooked.

An omelet object has the following interfaces: get_kind() - returns a string with the type of omelet set_kind(kind) - sets the omelet to be the type named

set_new_kind(kind, ingredients) - lets you create an omelet

mix() - gets called after all the ingredients are gathered from the fridge cook() - cooks the omelet

>>> print “%s” % o.set_new_kind.__doc__

set_new_kind(name, ingredients) - create a new type of omelet that is called “name” and that has the ingredients listed in “ingredients”

You can display the remaining docstrings in the same way.

Exercise 5 solution

class Recipe: “””

This class houses recipes for use by the Omelet class “””

def __init__(self): self.set_default_recipes() return

def set_default_recipes(self):

self.recipes = {“cheese” : {“eggs”:2, “milk”:1, “cheese”:1}, “mushroom” : {“eggs”:2, “milk”:1, “cheese”:1,

“mushroom”:2},

“onion” : {“eggs”:2, “milk”:1, “cheese”:1, “onion”:1}}

def get(self, name): “””

get(name) - returns a dictionary that contains the ingredients needed to make the omelet in name.

When name isn’t known, returns False “””

try:

recipe = self.recipes[name] return recipe

except KeyError: return False

def create(self, name, ingredients): “””

create(name, ingredients) - adds the omelet named “name” with the ingredients

“ingredients” which is a dictionary. “””

self.recipes[name] = ingredients

583

TEAM LinG

Appendix A

Exercise 6 solution

Note that the order of parameters in the interface for the class has now been changed, because you can’t place a required argument after a parameter that has an optional default value.

When you test this, remember that you now create an omelet with a recipe as its mandatory parameter.

def __init__(self, recipes, kind=”cheese”): “””__init__(self, recipes, kind=”cheese”)

This initializes the omelet class to default to a cheese omelet.

“””

self.recipes = recipes self.set_kind(kind)

return

def set_new_kind(self, name, ingredients): “””

set_new_kind(name, ingredients) - create a new type of omelet that is called “name” and that has the ingredients listed in “ingredients”

“””

self.recipes.create(name, ingredients) self.set_kind(name)

return

def __known_kinds(self, kind): “””

__known_kinds(kind) - checks for the ingredients of “kind” and returns them returns False if the omelet is unknown.

“””

return self.recipes.get(kind)

Chapter 7

Exercise 1 solution

Remember that you’re not a regular user of your class when you write tests. You should feel free to access internal names if you need to!

if __name__ == ‘__main__’: r = Recipe()

if r.recipes != {“cheese” : {“eggs”:2, “milk”:1, “cheese”:1}, “mushroom” : {“eggs”:2, “milk”:1, “cheese”:1,

“mushroom”:2},

“onion” : {“eggs”:2, “milk”:1, “cheese”:1, “onion”:1}}: print “Failed: the default recipes is not the correct list”

cheese_omelet = r.get(“cheese”)

if cheese_omelet != {“eggs”:2, “milk”:1, “cheese”:1}:

print “Failed: the ingredients for a cheese omelet are wrong” western_ingredients = {“eggs”:2, “milk”:1, “cheese”:1, “ham”:1, “peppers”:1,

“onion”:1}

r.create(“western”, western_ingredients) if r.get(“western”) != western_ingredients:

584

TEAM LinG

Answers to Exercises

print “Failed to set the ingredients for the western” else:

print “Succeeded in getting the ingredients for the western.”

Exercise 2 solution

At the end of the Fridge module, insert the following code. Note the comment about changing the add_many function to return True. If you don’t do that, add_many will return None, and this test will always fail!

if __name__ == ‘__main__’:

f = Fridge({“eggs”:10, “soda”:9, “nutella”:2}) if f.has(“eggs”) != True:

print “Failed test f.has(‘eggs’)” else:

print “Passed test f.has(‘eggs’)” if f.has(“eggs”, 5) != True:

print “Failed test f.has(‘eggs’, 5)” else:

print “Passed test f.has(‘eggs’, 5)”

if f.has_various({“eggs”:4, “soda”:2, “nutella”:1}) != True:

print ‘Failed test f.has_various({“eggs”:4, “soda”:2, “nutella”1})’ else:

print ‘Passed test f.has_various({“eggs”:4, “soda”:2, “nutella”1})’

#Check to see that when we add items, that the number of items in the fridge

#is increased!

item_count = f.items[“eggs”] if f.add_one(“eggs”) != True:

print ‘Failed test f.add_one(“eggs”)’ else:

print ‘Passed test f.add_one(“eggs”)’ if f.items[“eggs”] != (item_count + 1):

print ‘Failed f.add_one() did not add one’ else:

print ‘Passed f.add_one() added one’ item_count = {}

item_count[“eggs”] = f.items[“eggs”] item_count[“soda”] = f.items[“soda”]

# Note that the following means you have to change add_many to return True! if f.add_many({“eggs”:3,”soda”:3}) != True:

print ‘Failed test f.add_many({“eggs”:3,”soda”:3})’ else:

print ‘Passed test f.add_many({“eggs”:3,”soda”:3})’ if f.items[“eggs”] != (item_count[“eggs”] + 3):

print “Failed f.add_many did not add eggs” else:

print “Passed f.add_many added eggs”

if f.items[“soda”] != (item_count[“soda”] + 3): print “Failed f.add_many did not add soda”

else:

print “Passed f.add_many added soda”

item_count = f.items[“eggs”] if f.get_one(“eggs”) != True:

585

TEAM LinG

Appendix A

print ‘Failed test f.get_one(“eggs”)’ else:

print ‘Passed test f.get_one(“eggs”)’ if f.items[“eggs”] != (item_count - 1):

print “Failed get_one did not remove an eggs” else:

print “Passed get_one removed an eggs”

item_count = {}

item_count[“eggs”] = f.items[“eggs”] item_count[“soda”] = f.items[“soda”] eats = f.get_many({“eggs”:3, “soda”:3})

if eats[“eggs”] != 3 or eats[“soda”] != 3:

print ‘Failed test f.get_many({“eggs”:3, “soda”:3})’ else:

print ‘Passed test f.get_many({“eggs”:3, “soda”:3})’

if f.items[“eggs”] != (item_count[“eggs”] - 3): print “Failed get many didn’t remove eggs”

else:

print “Passed get many removed eggs”

if f.items[“soda”] != (item_count[“soda”] - 3): print “Failed get many didn’t remove soda”

else:

print “Passed get many removed soda”

Exercise 3 solution

You can try to generate errors by mistyping the name of a key in one place in the module, and confirming that this results in your tests warning you. If you find situations that these tests don’t catch, you should try to code a test for that situation so it can’t ever catch you.

Chapter 8

Exercise 1 solution

Here’s a simple but inefficient way to solve the problem:

import os

def print_dir(dir_path):

#Loop through directory entries, and print directory names. for name in sorted(os.listdir(dir_path)):

full_path = os.path.join(dir_path, name) if os.path.isdir(full_path):

print full_path

#Loop again, this time printing files.

for name in sorted(os.listdir(dir_path)): full_path = os.path.join(dir_path, name) if os.path.isfile(full_path):

print full_path

586

TEAM LinG

Answers to Exercises

Here’s the extra-credit solution, which only scans and sorts the directory once:

import os

def print_dir(dir_path):

#Loop through directory entries. Since we sort the combined

#directory entries first, the subdirectory names and file names

#will each be sorted, too.

file_names = []

for name in sorted(os.listdir(dir_path)): full_path = os.path.join(dir_path, name) if os.path.isdir(full_path):

# Print subdirectory names now. print full_path

elif os.path.isfile(full_path):

# Store file names for later. file_names.append(full_path)

# Now print the file names. for name in file_names:

print name

Exercise 2 solution

import os import shutil

def make_version_path(path, version): if version == 0:

return path else:

return path + “.” + str(version)

def rotate(path, max_keep, version=0): “””Rotate old versions of file ‘path’.

Keep up to ‘max_keep’ old versions with suffixes .1, .2, etc.

Larger numbers indicate older versions.”””

src_path = make_version_path(path, version) if not os.path.exists(src_path):

# The file doesn’t exist, so there’s nothing to do. return

dst_path = make_version_path(path, version + 1) if os.path.exists(dst_path):

# There already is an old version with this number. What to do? if version < max_keep - 1:

# Renumber the old version. rotate(path, max_keep, version + 1)

else:

# Too many old versions, so remove it. os.remove(dst_path)

shutil.move(src_path, dst_path)

587

TEAM LinG

Appendix A

Exercise 3 solution

Here is the program to add an entry to the diary. The diary data is stored in a filename’s diarydata.pickle.

import time import os import pickle

diary_file = “diary-data.pickle”

# Does the diary

file exist?

if os.path.exists(diary_file):

# Yes. Load

it.

diary_data =

pickle.load(file(diary_file))

else:

 

# No. Start

a new diary.

diary_data =

[]

# Get the current date and time. date_and_time = time.ctime(time.time())

#Ask the user to input the diary text. text = raw_input(“Your thoughts today? “)

#Add the entry to the diary.

diary_data.append((date_and_time, text))

# Write the diary data. pickle.dump(diary_data, file(diary_file, “w”))

Following is the program to print the diary:

import pickle

# Load the diary data.

diary_data = pickle.load(file(“diary-data.pickle”))

# Print the diary entries, most recent first. for date_and_time, text in reversed(diary_data):

print “Thoughts on %s:” % date_and_time print “%s” % text

print

Chapter 10

Exercise 1 solution

You get access to the functionality with a module by importing the module or items from the module.

Exercise 2 solution

If you define the variable __all__, you can list the items that make up the public API for the module. For example:

__all__ = [‘Meal’,’AngryChefException’, ‘makeBreakfast’,

‘makeLunch’, ‘makeDinner’, ‘Breakfast’, ‘Lunch’, ‘Dinner’]

588

TEAM LinG

Answers to Exercises

If you do not define the __all__ variable (although you should), the Python interpreter looks for all items with names that do not begin with an underscore.

Exercise 3 solution

The help function displays help on any module you have imported. The basic syntax follows:

help(module)

You can also use the pydoc command, not covered in this chapter.

Exercise 4 solution

Look in the directories listed in the variable sys.path for the locations of modules on your system. You need to import the sys module first.

Exercise 5 solution

Any Python commands can be placed in a module. Your modules can have Python commands, Python functions, Python variables, Python classes, and so on. In most cases, though, you want to avoid running commands in your modules. Instead, the module should define functions and classes and let the caller decide what to invoke.

Chapter 11

Exercise 1 solution

import os, os.path import re

def print_pdf (arg, dir, files): for file in files:

path = os.path.join (dir, file) path = os.path.normcase (path)

if not re.search (r”.*\.pdf”, path): continue if re.search (r” “, path): continue

print path

os.path.walk (‘/’, print_pdf, 0)

Note how this example just changes the name of the directory to start processing with the os.path.walk function.

Exercise 2 solution

import os, os.path import re

def print_pdf (arg, dir, files): for file in files:

589

TEAM LinG

Appendix A

path = os.path.join (dir, file) path = os.path.normcase (path)

if not re.search (r”.*\.pdf”, path): continue if not re.search (r”boobah”, path): continue

print path

os.path.walk (‘.’, print_pdf, 0)

This example just includes an additional test in the print_pdf function.

Exercise 3 solution

import os, os.path import re

def print_pdf (arg, dir, files): for file in files:

path = os.path.join (dir, file) path = os.path.normcase (path)

if not re.search (r”.*\.pdf”, path): continue if re.search (r”boobah”, path): continue

print path

os.path.walk (‘.’, print_pdf, 0)

Note how this example simply removes the not from the second test.

Chapter 13

Exercise 1 solution

The first step is to write a Glade interface. This should take just a few clicks now that you’re familiar with the tools. This GUI is very similar to our previous pyRAP GUI, so we’ll just show the finished project (see Figure A-1). Save that Glade project to the current directory, and we’ll write some code to use it.

Figure A-1

590

TEAM LinG