Homework 9: Velma’s Mystery Library
Due: Tuesday November 19, 2019 at 9:00PM EST.

Handin
Please do not have print statements in your final submission if they are not required. They will break our autograder :( Also, please make sure your final submission has appropriate indentation, and correct function names.
Handin these files to Gradescope
library.py
test_library.py
README.txt
The Assignment
Velma just opened up a library of rare mystery books! She wants to let people take out books from her library, but she needs to keep close tabs on the books since they’re highly sought-after. Help Velma create a system to organize her library and keep track of which books have been checked out by whom!
Field Updates and Memory
This assignment explores sharing of data as reflected in the contents of memory. For this part of the assignment we will work with dataclasses for (library) books and patrons (people who check out library books). Here are our data classes:
from dataclasses import dataclass
@dataclass
class Patron:
name: str
books_out: list
@dataclass
class Book:
title: str
author: str
checked_out: bool = False
borrower: Patron = None
replacement_fee: float = 100.0
The idea here is that when a patron checks out a book, the book is marked as checked out and the book is stored in the patron’s list of checked-out books. When a patron returns a book, the book is marked as checked in and removed from the patron’s list.
Note: In the Book
dataclass, we see a new feature: we can give fields default values that get set whenever you create a value of a dataclass. To create a Book
, we only provide the title and author data; the other two fields are created and set automatically. For example, here is a library catalog with four books (all with 1-word titles):
clean_catalog = [Book("The Mysterious Affair at Styles", "Agatha Christie"),
Book("The Adventures of Sherlock Holmes", "Arthur Conan Doyle"),
Book("The Secret of the Old Clock", "Carolyn Keene"),
Book("Crooked House", "Agatha Christie")]
Programs with Mutation
Write the following five programs in library.py
. You’ll need the usual imports:
from dataclasses import dataclass
Addition: Use the function headers given below the questions, adding type annotations where necessary (this is to make sure you write functions with inputs in the correct order so we can test them).
-
find_books
, which takes a list of books and a search term and returns the list of books with the given term in the title or author fields.
-
check_out
, which takes a book and a patron and updates both to check out the book out to the patron. Nothing gets returned. Don’t check for potential errors, just update the fields to check out the book.
-
check_in
, which takes a book and a patron and updates both to indicate that the patron has returned the book. The borrower
field of the Book
should be set to None
. Nothing gets returned. Don’t check for potential errors, just update the fields to check in the book.
-
display_books
, which takes a list of books and prints out a summary of each book, each book on one line. This gives a more readable view of a list of books than just printing out the entire list. The summary for one book should look like:
Crooked House by Agatha Christie [not available]
[not available] means the book is checked out. Print [available] for a book that is not checked out.
-
update_replacement_fee
, which takes a list of books and a dollar amount, and increases the replacement fee of each book in the list by that dollar amount. This function does not return anything, it just updates the list of books.
-
cheapest_replacement_fee
, which takes a list of books and returns the book with the lowest replacement fee. If there are no books, return None.
-
total_replacement_fee
, which takes a patron and returns the total replacement fee a patron would have to pay if they lost all of the books they currently have checked out. If a Patron has no books checked out, the total_replacement_fee
function should return 0.0.
Remember to add type annotations!
def find_books(books, query):
def check_out(book, patron):
def check_in(book, patron):
def display_books(books):
def update_replacement_fee(books, amount):
def cheapest_replacement_fee(books):
def total_replacement_fee(patron):
What’s Going on in Memory?
Here, we have provided three programs that use the functions you have just written. At the end of each program is a question marked with comment characters (#). Answer each of the questions. For questions that ask you to write a line of code, edit the programs to answer the questions (in library.py
). For questions that ask you to write out contents of memory, put your answers in your README.
Refer to the notes from Wednesday’s lecture for the format you should use to write out the contents of memory.
Note: The top of each program shows how you can make a copy of an existing value for purposes of testing or experimentation. Here, we copy the clean_catalog
, to give us a local version for each program. You’ll need to add the following import to the top of your file to get the copy operation:
from copy import deepcopy
def program1():
"""Sample program #1"""
catalog = deepcopy(clean_catalog)
Josh = Patron("Josh", [])
check_out(catalog[0], Josh)
check_out(catalog[1], Josh)
def program2():
"""Sample program #2"""
catalog = deepcopy(clean_catalog)
check_out(catalog[0], Patron("Kathi", []))
check_out(catalog[2], Patron("Kathi", []))
def program3():
"""Sample program #3"""
catalog = deepcopy(clean_catalog)
Julia = Patron("Julia", [])
Nam = Patron("Nam", [])
search = find_books(catalog, "Holmes")
check_out(search[0], Julia)
check_out(search[0], Nam)
print("Julia's books:")
display_books(Julia.books_out)
print("Nam's books")
display_books(Nam.books_out)
Testing
In Python, you’ll need to create a separate file to run the tests for all of your functions. For this homework, your testing file should be named test_library.py
and should contain a separate function to test each of the functions in library.py
. You will need to import library.py
in your testing file in order to run your tests.
For example, in test_library.py
, write a function test_check_out
, which takes no inputs but runs tests to show that check_out
is working properly. Write a test function like this for each of your functions in library.py
except for display_books
.
In writing your tests, think back to the example from lecture where we wrote separate tests for individual fields. Develop your tests to check what should (and should not) have happened in each field after a check_out
.
Tips & Tricks
You can build messages to print using a combination of the built-in function str
, which converts its argument to a string, and +
to concatenate strings. Here’s an example:
print("Today is " + str(date(2018, 7, 26)))
There are also more specialized ways to format strings, which, though not necessary for this course, can be extremely useful for everyday Python usage. Check out this link to learn about f-Strings
(don’t worry about the “class
” stuff).
README.txt
No additional responses required for this week! Still submit a README though (we use it to track late days and collaboration stuff)!
Brown University CSCI 0111 (Fall 2019)
Do you have feedback? Fill out this form.
Homework 9: Velma’s Mystery Library
Due: Tuesday November 19, 2019 at 9:00PM EST.
Handin
Please do not have print statements in your final submission if they are not required. They will break our autograder :( Also, please make sure your final submission has appropriate indentation, and correct function names.
Handin these files to Gradescope
library.py
test_library.py
README.txt
The Assignment
Velma just opened up a library of rare mystery books! She wants to let people take out books from her library, but she needs to keep close tabs on the books since they’re highly sought-after. Help Velma create a system to organize her library and keep track of which books have been checked out by whom!
Field Updates and Memory
This assignment explores sharing of data as reflected in the contents of memory. For this part of the assignment we will work with dataclasses for (library) books and patrons (people who check out library books). Here are our data classes:
from dataclasses import dataclass @dataclass class Patron: name: str books_out: list @dataclass class Book: title: str author: str checked_out: bool = False borrower: Patron = None replacement_fee: float = 100.0
The idea here is that when a patron checks out a book, the book is marked as checked out and the book is stored in the patron’s list of checked-out books. When a patron returns a book, the book is marked as checked in and removed from the patron’s list.
Note: In the
Book
dataclass, we see a new feature: we can give fields default values that get set whenever you create a value of a dataclass. To create aBook
, we only provide the title and author data; the other two fields are created and set automatically. For example, here is a library catalog with four books (all with 1-word titles):clean_catalog = [Book("The Mysterious Affair at Styles", "Agatha Christie"), Book("The Adventures of Sherlock Holmes", "Arthur Conan Doyle"), Book("The Secret of the Old Clock", "Carolyn Keene"), Book("Crooked House", "Agatha Christie")]
Programs with Mutation
Write the following five programs in
library.py
. You’ll need the usual imports:from dataclasses import dataclass
Addition: Use the function headers given below the questions, adding type annotations where necessary (this is to make sure you write functions with inputs in the correct order so we can test them).
find_books
, which takes a list of books and a search term and returns the list of books with the given term in the title or author fields.check_out
, which takes a book and a patron and updates both to check out the book out to the patron. Nothing gets returned. Don’t check for potential errors, just update the fields to check out the book.check_in
, which takes a book and a patron and updates both to indicate that the patron has returned the book. Theborrower
field of theBook
should be set toNone
. Nothing gets returned. Don’t check for potential errors, just update the fields to check in the book.display_books
, which takes a list of books and prints out a summary of each book, each book on one line. This gives a more readable view of a list of books than just printing out the entire list. The summary for one book should look like:[not available] means the book is checked out. Print [available] for a book that is not checked out.
update_replacement_fee
, which takes a list of books and a dollar amount, and increases the replacement fee of each book in the list by that dollar amount. This function does not return anything, it just updates the list of books.cheapest_replacement_fee
, which takes a list of books and returns the book with the lowest replacement fee. If there are no books, return None.total_replacement_fee
, which takes a patron and returns the total replacement fee a patron would have to pay if they lost all of the books they currently have checked out. If a Patron has no books checked out, thetotal_replacement_fee
function should return 0.0.Function headers
Remember to add type annotations!
def find_books(books, query): def check_out(book, patron): def check_in(book, patron): def display_books(books): def update_replacement_fee(books, amount): def cheapest_replacement_fee(books): def total_replacement_fee(patron):
What’s Going on in Memory?
Here, we have provided three programs that use the functions you have just written. At the end of each program is a question marked with comment characters (#). Answer each of the questions. For questions that ask you to write a line of code, edit the programs to answer the questions (in
library.py
). For questions that ask you to write out contents of memory, put your answers in your README.Refer to the notes from Wednesday’s lecture for the format you should use to write out the contents of memory.
Note: The top of each program shows how you can make a copy of an existing value for purposes of testing or experimentation. Here, we copy the
clean_catalog
, to give us a local version for each program. You’ll need to add the following import to the top of your file to get the copy operation:from copy import deepcopy def program1(): """Sample program #1""" catalog = deepcopy(clean_catalog) Josh = Patron("Josh", []) check_out(catalog[0], Josh) check_out(catalog[1], Josh) # FILL in the blank so the following test passes # (take the test out of comment when you are done) # assert Josh.books_out == ______ def program2(): """Sample program #2""" catalog = deepcopy(clean_catalog) check_out(catalog[0], Patron("Kathi", [])) check_out(catalog[2], Patron("Kathi", [])) # WRITE out the memory contents at this point # You don't need to write out the # original catalog in memory, just the copy. # # Either write a statement to print all the books Kathi # has checked out, or write a comment explaining why # this can't be done. # __________________________ def program3(): """Sample program #3""" catalog = deepcopy(clean_catalog) Julia = Patron("Julia", []) Nam = Patron("Nam", []) search = find_books(catalog, "Holmes") check_out(search[0], Julia) check_out(search[0], Nam) print("Julia's books:") display_books(Julia.books_out) print("Nam's books") display_books(Nam.books_out) # WRITE out the memory contents at this point # You don't need to write out the # original catalog in memory, just the copy. # # In a few sentences, discuss whether the # memory contents look as you'd expect # for a program that properly checked books # in and out. If not, what program error # does this suggest?
Testing
In Python, you’ll need to create a separate file to run the tests for all of your functions. For this homework, your testing file should be named
test_library.py
and should contain a separate function to test each of the functions inlibrary.py
. You will need to importlibrary.py
in your testing file in order to run your tests.For example, in
test_library.py
, write a functiontest_check_out
, which takes no inputs but runs tests to show thatcheck_out
is working properly. Write a test function like this for each of your functions inlibrary.py
except fordisplay_books
.In writing your tests, think back to the example from lecture where we wrote separate tests for individual fields. Develop your tests to check what should (and should not) have happened in each field after a
check_out
.Tips & Tricks
String Formatting
You can build messages to print using a combination of the built-in function
str
, which converts its argument to a string, and+
to concatenate strings. Here’s an example:print("Today is " + str(date(2018, 7, 26)))
There are also more specialized ways to format strings, which, though not necessary for this course, can be extremely useful for everyday Python usage. Check out this link to learn about
f-Strings
(don’t worry about the “class
” stuff).README.txt
No additional responses required for this week! Still submit a README though (we use it to track late days and collaboration stuff)!