CS21 Lab 10: Classes and Objects
Due Saturday, December 5, before midnight
Read through this entire lab writeup BEFORE you begin to write any code. Taking the time to thoroughly understand what you are trying to accomplish will allow you to more effectively implement the code.
Checkpoint
At the end of your lab session, be sure to run handin21
.
Your lab instructor will check your files, which should reflect that you have made non-trivial progress (in python or pseudocode) towards the solution. Note that if you have not made much progress towards your solution, we expect that you would have been actively seeking help during your lab over Slack.
A portion of your final lab grade is dependent on this checkpoint.
If there are circumstances which prevent you from making substantial progress on this lab, please contact your lab instructor as soon as possible.
Goals
-
gain experience writing classes
-
gain experience reading and using classes
1. Introduction
In this lab, you will build an e-reader called the Swindle (any resemblance to current e-readers is completely coincidental). You will use object-oriented programming to create two classes.
The first class you will develop is the Book
class that encapsulates
one electronic book (or ebook). We have made several free
ebooks available for you to load and experiment with to get your
Book
class working.
The second class you will develop is the Swindle
class that
encapsulates the concept of an e-reader. You will be able to perform
several core operations of an e-reader, including buying books,
picking a book from your virtual shelf, and reading a book.
To get started, take note of the files that we have provided for you:
-
book.py
- the definition of theBook
class to be completed by you -
swindle.py
- the definition of theSwindle
class to be completed by you (we give you a partially implemented constructor and a few other completed methods) -
bookdb.txt
- a file containing information about all of the books available for download -
ereader.py
- the main program to create aSwindle
and interact with the device (we give you all of this)
1.1. Sample runs
Read through the two sample runs provided below. The first one is annotated with comments so that you can see how the e-reader should operate, and understand which parts you need to implement and which parts are already implemented for you. The second one is an uninterrupted run.
2. Complete the Book
class
A Book
object represents an electronic book to read on your
e-reader. You should define your class such that each book maintains
the following data (also called instance variables):
-
title (string) — the title of the book
-
author (string) — the author of the book
-
year (int) — the year the book was published
-
filename (string) — where the book is stored on the CS lab machines, for example:
"/usr/local/doc/alice.txt"
-
bookmark (int) — the page number where the owner left off when last reading the book
Your Book
class should define the following methods:
-
_init_
: constructor that initializes aBook
object, where the parameters specify the title, author, year published, and the name of the file containing the book. You should initialize all data fields for the object in this function. Remember to useself.
in front of every data field associated with the class. The bookmark data field for a newly createdBook
object should be initialized to page 0, since it’s a new book. -
_str_
: method that returns a string representation of aBook
object. Your method should return a string containing the title, author, and date published in a readable format. Use string formatting to give the title a width of 25 and the author a width of 25. When you print information about multiple books, this will line the book information up nicely as shown below:
Alice in Wonderland by Lewis Carroll (1865) Gettysburg Address by Abe Lincoln (1863)
-
Getter methods for all of the object’s data (for example:
get_title()
,get_author()
, etc) -
Both getter and setter methods for the object’s bookmark data
-
get_text()
: method to retrieve the entire contents of the book as a single string. This method will need to:-
Open the filename stored in the
Book
object -
Ignore any lines in the file that start with a pound sign (#)
-
Store all lines of the file in one long string, where each line is separated by newline characters
\n
-
Close the file
-
For example, if the file contained the "Roses are red…" poem:
# Here is a silly poem Roses are red, Violets are blue. # Second verse Sugar is sweet, And so are you!
Then getText()
would return a string that looks like this, where
the comment lines (starting with the pound sign) have been removed:
"Roses are red,\nViolets are blue.\nSugar is sweet,\nAnd so are you!\n"
When you print this string it will look like this:
Roses are red, Violets are blue. Sugar is sweet, And so are you!
2.1. Incrementally test the Book
class
As you complete each method of the Book
class you should test it.
Notice that at the bottom of your book.py
file we have provided some
initial tests. When you do $ python3 book.py
this test code
will be executed.
if __name__ == '__main__':
print("Testing the Book class...")
mybook = Book("Gettysburg Address", "Abe Lincoln", 1863,
"/usr/local/doc/GettysburgAddress")
print("Testing __str__...")
print(mybook)
print("Testing get_filename...")
print(mybook.get_filename())
print("Testing get_text...")
text = mybook.get_text()
print(text[:105]) #only print the first couple of lines
print("bookmark is:", mybook.get_bookmark())
mybook.set_bookmark(12)
print("now bookmark is:", mybook.get_bookmark())
################ Write additional tests below ###################
Enhance this test code by adding a number of your own tests.
Do not move on to the Swindle
class until you are sure that your
Book
class is working correctly!
3. Complete the Swindle
class
The Swindle
class defines an e-reader device. Every instance must
maintain a few pieces of data:
-
owner (string) — the owner’s name
-
available_books (list of
Book
objects) — books available for sale -
owned_books (list of
Book
objects) — books owned by the user -
page_length (int) - the number of lines to display per page; 20 is a good default page length
3.1. The constructor
We have provided the beginning of the class definition by defining the constructor (which includes the functionality for loading the database of available books). You only need to add a few lines of code where you see the comment:
#TODO: using the information just obtained from the file,
# create a Book object with this data and add it to the
# available_books list
When first creating a Swindle
object, the user does not own any books,
and all books in the database should be considered books available for
purchase.
It is important to note that both the variables available_books
and owned_books
are lists of Book
objects. Here is a clear example
of the power of encapsulation. A Book
object stores all of the
important information and functionality needed to interact with a book.
By keeping lists of Book
objects, the Swindle
class can easily
implement the functionality for reading these books.
3.2. Methods provided for you to display a book
We have also provided the methods display_text()
, display_page()
,
and get_letter()
. These methods take care of the details involved in
displaying a certain number of lines from the book. You do not need
to change these methods. The method display_text()
is the method
you will call to allow the user to read one of their books. This
method calls the method display_page()
to show a single page at a
time. It also calls the method get_letter()
to determine what the
user wants to do next. Once the user decides to quit reading a
particular book, the display_text()
method returns the current page
number of the book.
3.3. Methods you must implement
Your Swindle
class should define the following methods:
-
show_owned()
: prints all owned titles (see sample output) -
show_available()
: prints all available (but not owned) titles -
get_owner()
: returns the owner’s name -
buy()
: allows the user to purchase a book. This method should print all available titles and allow the user to choose one book. Hint: use theshow_available()
method as a helper. If the choice is valid, the purchased book should be added to the list of owned books and removed from the list of available books. You can use thepop()
method of lists to accomplish this, as the following example demonstrates. You should print a message verifying that purchase was successful.
$ python3
>>> ls = ["this", "is", "a", "test"]
>>> word = ls.pop(1) #remove and return the item at index 1
>>> word
'is'
>>> ls
['this', 'a', 'test']
-
read()
: allows the user to choose a book to read. This method should print all owned books and allow the user to choose one book. Hint: Use theshow_owned()
method as a helper. It then calls thedisplay_text()
method, using the appropriateBook
object as an argument todisplay_text()
. When the user quits reading a book, set the bookmark to the current page, and print a message verifying that the bookmark was set.
For both the buy()
and read()
methods, you should ensure that
the user selects a valid book number from the menu. You can assume
that the user always enters an integer.
3.4. Incrementally test the Swindle
class
As you complete each method of the Swindle
class you should test it.
Notice that at the bottom of your swindle.py
file we have provided some
initial tests. When you do $ python3 swindle.py
this test code
will be executed.
if __name__ == '__main__':
print("Testing the Swindle class...")
myswindle = Swindle()
print("Testing show_available...")
myswindle.show_available()
print("Testing show_owned...")
myswindle.show_owned()
################ Write additional tests below ###################
4. Putting it all together
Once you have written (and thoroughly tested!) the Book
and
Swindle
classes, according to the above requirements, you should be
able to successfully run the main e-reader program: $ python3
ereader.py
Here again is the sample run demonstrating how the e-reader should behave.
Test out all of features of your classes by trying every possible menu option from the e-reader. Be sure to gracefully handle these edge cases:
-
when the user wants to buy books, but none are available
-
when the user wants to read books, but none are available
5. Optional Enhancements
This section is completely optional. Only attempt this once you have successfully completed all of the required portions of the lab. Because this is optional extension, we are leaving a lot of the details for you to figure out on your own.
If you wish to attempt this part, be sure to make copies of your orignal code as shown below. Only modify the copies, leaving the original solution alone.
$ cd cs21/labs/10 $ cp swindle.py enhancedSwindle.py $ cp ereader.py enhancedEreader.py
The original version of the e-reader starts from scratch every time, which is unrealistic. Instead, we would like the e-reader to remember the owner’s name, the books that have been purchased (and what page number the owner is on), as well as the books that are still available.
Here are several sample runs demonstrating how the enhanced e-reader should behave.
To accomplish this you will need to learn how to write to a file. Below is a short example program showing how to do this.
def main():
name = "Sedi"
age = 21
fp = open("test.txt", "w")
fp.write("%s is %d years old\n" % (name, age))
fp.write("this is a test\n")
fp.write("here's another line\n")
fp.write("goodbye\n")
fp.close()
main()
Here’s what the file test.txt
would now contain:
Sedi is 21 years old this is a test here's another line goodbye
One other new python feature you’ll need is to be able to check whether a particular file exists or not. You can try this in the python intepreter:
$ python3
>>> from os.path import isfile
>>> isfile("ereader.py")
True
>>> isfile("foobar")
False
Now that you know how to write a file and how to check whether a file exists, you are ready to implement the enhanced e-reader. The basic idea is as follows.
-
Every time the user quits the e-reader, write out a status file that stores all of the relevant information about the e-reader. You can decide on the format for this status file.
-
When you start up the e-reader, check if this status file exists.
-
If not, everything works as it did in the original e-reader; you’ll need to read in the available books from the file
bookdb.txt
. -
If it does exist, welcome the owner back and read in the status information from the file you created (you can ignore the file
bookdb.txt
).
Without too much effort you’ll have an enhanced e-reader that is much more like an actual device.
Answer the Questionnaire
Please edit
the Questions-10.txt
file in your cs21/labs/10
directory
and answer the questions in that file.
Once you’re done with that, run handin21
again.
Turning in your labs….
Remember to run handin21
to turn in your lab files!
You may run handin21
as many times as you want. Each time it will
turn in any new work. We recommend running handin21
after
you complete each program or after you complete significant
work on any one program.