Due: Tuesday, September 11, in my office by 5:15 p.m.
Goals:Collaboration: You should work in pairs for this lab. You may discuss the assignment with anyone you wish. You may obtain help from anyone you wish, but you should clearly document that help. You need turn in only one assignment per pair.
Contents:Our overall goal in this lab is to build the final version of the GuitarShop application from OOA&D, Chapter 1, in Python. Along the way, we'll explore some ideas in the interactive Python interpreter.
Open a terminal window and change to the directory where you
are keeping files for this course. Start the interactive
Python interpreter by typing python.
Open another terminal window (or tab). Use your favorite text
editor to begin editing a file named guitarshop.py.
Recall that we defined Type, Builder, and Wood as enumerated types. (Why?) Does Python have enumerated types? If not, how could you accomplish the same goal?
In guitarshop.py, try defining
a Type enumeration that includes the values ELECTRIC and
ACCOUSTIC.
Load the guitarshop module in python using "import
guitarshop" and give it a try. (Note that, when you load a module using import, you must prefix the names of classes with the module name -- e.g,. you refer to the Type class as guitarshop.Type).
We'll pause after a few minutes and talk about this as a class.
OK, now implement all three enumerated types: Type, Builder, and Wood. Here are the values for the enumerations:
Type
| ACCOUSTIC | 'accoustic' |
| ELECTRIC | 'electric' |
Builder
| FENDER | 'Fender' |
| MARTIN | 'Martin' |
| GIBSON | 'Gibson' |
| COLLINGS | 'Collings' |
| OLSON | 'Olson' |
| RYAN | 'Ryan' |
| PRS | 'PRS' |
| ANY | 'any' |
Wood
| INDIAN_ROSEWOOD | 'Indian rosewood' |
| BRAZILIAN_ROSEWOOD | 'Brazilian rosewood' |
| MAHOGANY | 'mahogany' |
| MAPLE | 'maple' |
| COCOBOLO | 'cocobolo' |
| CEDAR | 'cedar' |
| ADIRONDACK | 'adirondack' |
| ALDER | 'alder' |
| SITKA | 'sitka spruce' |
You can reload the guitarshop module in python using reload(guitarshop).
OOA&D, p. 39, shows the latest class diagram for
GuitarSpec. But it's missing some things we added at the end of the
chapter: the numStrings property and the matches(otherSpec)
method.
Draw a new class diagram for GuitarSpec that includes these methods. You'll refer to it in the next exercise.
In guitarshop.py, create a
GuitarSpec class. Define its __init__ method
and get methods for all the properties.
Reload the guitarshop module in python using reload(guitarshop) and
give your new class a try!
Now, onto that new matches(otherSpec)
method... We need to verify that each of the properties of self
and otherSpec match. For builder,
type, backWood, and topWood,
it's easy: these are all enumerated types, and we can check their
equality with the == and !=
operators. numStrings is a number, so it's
easy too.
What about model? That could be any
string. The Java code uses the following test:
((model != null) && !(model.equals("")) && (!model.equals(otherSpec.model))) [OOA&D, p. 45]
None.)help(str) in the Python interpreter.)GuitarSpec.matches(otherSpec)
method.matches.Since we encapsulated most of a guitar's properties into the GuitarSpec class, the Guitar class is very simple! The class diagram on p. 38 of OOA&D is still correct. Implement the Guitar class.
As we can see in the class
diagram on p. 39 of OOA&D, the Inventory class has one
property, a
list of guitars, and three methods: addGuitar(...)
, getGuitar(serialNumber), and search(guitarSpec).
You should have everything you need now to implement the Inventory
class. Believe it or not, you won't need to write very much code. Go to
it!
Hmm, we've been leaving out something important. We've been doing some little tests as we go along, but do the Guitar and Inventory classes work? And what if we decide to change something in GuitarSpec---how do we know that still works? It would be helpful to have some automated tests. Luckily, the authors of OOA&D already wrote some, so we'll just translate them into Python.
guitarshop.py.def createTestInventory():
"Create an inventory of guitars for testing this module."
inventory = Inventory()
inventory.addGuitar(Guitar('45790J', 1799.95,
GuitarSpec(Builder.FENDER,
'Stratocastor',
Type.ELECTRIC,
6,
Wood.ALDER,
Wood.ALDER)))
inventory.addGuitar(Guitar('23578Q', 1099.95,
GuitarSpec(Builder.FENDER,
'Fictocastor',
Type.ELECTRIC,
6,
Wood.ALDER,
Wood.ALDER)))
inventory.addGuitar(Guitar('34789A', 1499.95,
GuitarSpec(Builder.FENDER,
'Stratocastor',
Type.ELECTRIC,
6,
Wood.ALDER,
Wood.ALDER)))
inventory.addGuitar(Guitar('83959B', 1299.95,
GuitarSpec(Builder.MARTIN,
'JM',
Type.ACCOUSTIC,
6,
Wood.SITKA,
Wood.MAHOGANY)))
return inventory
if __name__ == '__main__':
inventory = createTestInventory()
whatErinLikes = GuitarSpec(Builder.FENDER, 'stratocastor', Type.ELECTRIC,
6, Wood.ALDER, Wood.ALDER)
matchingGuitars = inventory.search(whatErinLikes)
if len(matchingGuitars) > 0:
print 'Erin, you might like these guitars:'
# TODO: print out info for each matching guitar
else:
print 'Sorry, Erin, we have nothing for you.'
python
guitarshop.py. If all goes well, you'll see the following
output:Erin, you might like these guitars:Well, that's kind of helpful. We know some guitars matched, but it didn't tell us which ones.
Where the code above says TODO, fill in your own code to iterate over matching guitars and print some information about each one. Remember that you can use string formatting (see PPR, p. 14-15) to make your job easier. The output should look something like the following:
Erin, you might like these guitars:
We have a 6-string Fender Stratocastor Electric guitar:
Alder back and sides, Alder top.
You can have it for only $1799.95!
----
We have a 6-string Fender Stratocastor Electric guitar:
Alder back and sides, Alder top.
You can have it for only $1499.95!
----
map
and filter procedures already defined.
In the interpreter, define a new procedure, double(x),
that returns 2*x. Then write an expression
using map to double each item in the list [1,2,3].
map
to double each item in the list [1,2,3] without using the double
procedure.map that converts
each string in the list ['spam', 'eggs'] to
ALL UPPER CASE.filter
is a standard higher-order procedure that lets us pick out items from a
list that agree with some predicate. What do you think the following
expression will do?filter(lambda i: i%10 == 0, [0, 5, 10, 15, 20, 25, 30])Try it out. Did it do what you expected?
search
method of Inventory to use filter rather than
a for loop. Put those automated tests to work
by running python guitarshop.py
again---make sure that the code still works.Whew! Good work! You now know many of Python's features. For this final exercise, a couple of questions:
For extra credit, think of a way to refine the guitarshop code or tests that we didn't talk about in class. Implement this refinement (while ensuring your code still works correctly!) and tell me why it is better.
Capture your source code and its output in a single file by running the following commands:
script groupname.txt
cat guitarshop.py
python guitarshop.py
<CTRL-D>
To print the file, type
enscript -G -Pprintername groupname.txt
Turn in this paper printout to me along with your answers to the questions in the lab; you can slide it under my door if I'm not there.
Also email me a copy of your source code. Please put your code in the body of the message and put "CSC223-Lab-1" in the subject line.
Janet Davis (davisjan@cs.grinnell.edu)
Created August 14, 2007