You are going to implement software for your local library. The user of the software will be the librarian, who uses your program to issue library cards, check books out to patrons, check books back in, send out overdue notices, and open and close the library.
In a number of methods, we will make a distinction between what the program appears to do (its behavior), and what it actually does (its implementation). For example, when we "issue a library card" to a patron, we don't create some kind of a "library_card object" and give it to a patron object; the implementation will achieve the same result by simply recording the patron's name in a dictionary. The visible behavior is the same: A person who has been "issued a library card" will be able to check out books. Don't let yourself be confused by the terminology.
You should not need any additional classes, but if you would like additional methods, feel free to write (and test!) them.
class Calendar(object)date class, but to keep
things simple, we will just use an integer to keep
track of how many days have passed. There should be one and only one calendar. The first time the librarian opens the library, it should be day 1. class Book(object) title,
author, and due_date.
The due date is None if the book is not checked
out. class Patron(object)name and books_checked_out (a set of Book objects). A patron must "have a library
card" in order to check out books (in our program we won't use actual cards, we'll just keep a set of valid patrons.) A patron may have no more
than three books checked out at any time. class Library(object)main method. __init__(self)Library object (you should create exactly one of
these). It should create a global Calendar object, and set the following instance variables:
is_open -- initially False. patrons -- a set of patrons. patron_being_served -- initially None.response -- used to accumulate messages for later printing by main. collection -- a list of all books belonging to the library, initially empty. __init__ should not read in the book collection. This should be done by a separate method, read_book_collection(self), which should be called in main immediately after creating the Library. open(self)"The library is already open!". Otherwise, starts the day by advancing the Calendar, and setting the is_open flag."Today is day n."list_overdue_books(self)"No books are overdue.".Exception: "The library is not open.". issue_card(self, name_of_patron)"Library card issued to name_of_patron." or "name_of_patron already has a library card.".Exception: "The library is not open.". serve(self, name_of_patron)patron_being_served instance variable, if the patron has a library card; otherwise, returns "name_of_patron does not have a library card." If the patron does have a library card, the method should return
a multiline string containing "Now serving name_of_patron." plus a numbered list of books checked out to that patron, if any. Exception: "The library is not open."check_in(self, *book_numbers)book_numbers are taken from the list printed by the serve command. Checking in a Book will involve
both telling the Book that it is checked in and
returning the Book to this library's collection of available
Books."name_of_patron has returned n books.".Exception with an appropriate message:
"The library is not open.""No patron is currently being served.""The patron does not have book number."search(self, string)Books whose title or author (or both)
contains this string. For example, the string "tact" might
return, among other things, the book Contact, by Carl Sagan.
The search should be case-insensitive; that is, "saga"
would also return this book. Only books which are currently available
(not checked out) will be found. If there is more than one copy of a book (with the same title and same author), only one will be found. In addition, to keep from returning
too many books, require that the search string be at least 4 characters
long."No books found.""Search string must contain at least four characters."__str__ method.)check_out(self, *book_numbers)book_numbers could have been found by a recent call to the search method.
Checking out a book will involve both telling the book that it
is checked out and removing the book from this library's
collection of available books. "n books have been checked out to name_of_patron.".Exception with an appropriate message:
"The library is not open.""No patron is currently being served.""The library does not have book id."close(self)quit) can be used when the library is
closed."Good night.".Exception with the message "The library is not open." quit(self)"The library is now closed for renovations.".serve the patron. This will print a numbered list of books
checked out to that patron.check_in the books by the
numbers given above.serve the patron. You can ignore the list of books that this
may print out.search for a book wanted by
the patron (unless you already know its book_number from a previous search).check_out one or more books
by the numbers returned from the search command.search. |
Instance variables are variables that belong to an object, and instance methods are methods that are defined for an object. Instance variables and methods must be prefixed with self. , when used by the object itself. Local variables (including parameters) and global variables should not be prefixed with self. When an object uses the methods of another object, those methods must be prefixed by a variable that refers to the object; for example, book.get_title().
Most Library methods produce messages. When running the program normally, these messages should be printed. However, when these methods are called from unit test methods, they should not print anything. There are various ways to solve this problem; here are some.
print eval" does in the code below.) This approach is simple, but becomes messy if the method originally prints from more than one place.talk method accumulate messages in an instance variable, then later printed (and deleted) the messages in the main method.Three of the methods above, check_out, check_in, and renew, have an asterisk in front of the last parameter. That
asterisk is new syntax--it means that, when you call the
method, you can give as many book numbers as you please; you don't have to
give just one. Inside the method, the parameter book_numbers is a tuple of all the numbers
(zero or more) that you gave it.
Changes to the provided main method:
def main():
library = Library()
library.read_book_collection()
print len(library.collection), 'books in collection.'
print "Ready for input. Type 'help()' for a list of commands."
command = '\0'
while command != 'quit()':
try:
command = raw_input('\nLibrary command: ').strip()
if len(command) == 0:
print "What? Speak up!\n"
else:
print eval('library.' + command)
# or
eval('library.' + command)
print library.response
library.response = ''
except AttributeError, e:
print "Sorry, I didn't understand:", command
print "Type 'help()' for a list of the things I do understand.\n"
except RuntimeError, e:
print e
except Exception, e:
print "Unexpected error:"
print e # Delete this line after debugging your program
library.py, library_test.py, collection.txt.
Your program is due before