-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
279 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
import weakref | ||
import re | ||
|
||
class User(): | ||
def __init__(self, name, email): | ||
self.name = name | ||
assert ("@" in email and re.search(".com|.edu|.org", email)), "Invalid e-mail address format." | ||
self.email = email | ||
self.books = {} | ||
|
||
def get_email(self): | ||
return self.email | ||
|
||
def change_email(self, address): | ||
assert ("@" in email and re.search(".com|.edu|.org", email)), "Invalid e-mail address format." | ||
self.email = address | ||
print("E-mail address updated.") | ||
|
||
def read_book(self, book, rating=None): | ||
self.books[book] = rating | ||
|
||
def get_average_rating(self): | ||
sum = 0 | ||
num_rated_books = 0 | ||
for book in self.books.keys(): | ||
if self.books[book] != None: | ||
sum += self.books[book] | ||
num_rated_books += 1 | ||
return sum / num_rated_books | ||
|
||
def __repr__(self): | ||
return "User {name}, e-mail: {address}, books read: {num_books}".format(name=self.name, address=self.email, num_books=len(self.books)) | ||
|
||
def __eq__(self, other_user): | ||
return self.name == other_user.name and self.email == other_user.email | ||
|
||
class Book(): | ||
instances = [] | ||
|
||
def __init__(self, title, isbn, price): | ||
assert (isbn not in [instance.isbn for instance in self.__class__.instances]), "A Book object already exists with that ISBN!" | ||
self.title = title | ||
self.isbn = isbn | ||
self.price = price | ||
self.ratings = [] | ||
self.__class__.instances.append(weakref.proxy(self)) | ||
|
||
def get_title(self): | ||
return self.title | ||
|
||
def get_isbn(self): | ||
return self.isbn | ||
|
||
def get_price(self): | ||
return self.price | ||
|
||
def set_isbn(self, isbn): | ||
self.isbn = isbn | ||
print("Updated ISBN for {title}".format(title=self.title)) | ||
|
||
def add_rating(self, rating): | ||
if rating >= 0 and rating <= 4: | ||
self.ratings.append(rating) | ||
else: | ||
print("Invalid Rating") | ||
|
||
def get_average_rating(self): | ||
sum = 0 | ||
for rating in self.ratings: | ||
sum += rating | ||
return sum / len(self.ratings) | ||
|
||
def __repr__(self): | ||
return self.title | ||
|
||
def __hash__(self): | ||
return hash((self.title, self.isbn)) | ||
|
||
def __eq__(self, other_book): | ||
return self.title == other_book.title and self.isbn == other_book.isbn and self.price == other_book.price | ||
|
||
class Fiction(Book): | ||
def __init__(self, title, author, isbn, price): | ||
super().__init__(title, isbn, price) | ||
self.author = author | ||
|
||
def get_author(self): | ||
return self.author | ||
|
||
def __repr__(self): | ||
return "{title} by {author}".format(title=self.title, author=self.author) | ||
|
||
class Non_Fiction(Book): | ||
def __init__(self, title, subject, level, isbn, price): | ||
super().__init__(title, isbn, price) | ||
self.subject = subject | ||
self.level = level | ||
|
||
def get_subject(self): | ||
return self.subject | ||
|
||
def get_level(self): | ||
return self.level | ||
|
||
def __repr__(self): | ||
return "{title}, a {level} manual on {subject}".format(title=self.title, level=self.level, subject=self.subject) | ||
|
||
class TomeRater(): | ||
def __init__(self): | ||
self.users = {} | ||
self.books = {} | ||
|
||
def __repr__(self): | ||
return "Users: \n{users}\n\nBooks: \n{books}".format(users=self.users, books=self.books) | ||
|
||
def __eq__(self, other): | ||
if isinstance(other, self.__class__): | ||
return self.users == other.users and self.books == other.books | ||
return False | ||
|
||
def create_book(self, title, isbn, price): | ||
return Book(title, isbn, price) | ||
|
||
def create_novel(self, title, author, isbn, price): | ||
return Fiction(title, author, isbn, price) | ||
|
||
def create_non_fiction(self, title, subject, level, isbn, price): | ||
return Non_Fiction(title, subject, level, isbn, price) | ||
|
||
def add_book_to_user(self, book, email, rating=None): | ||
if email not in self.users: | ||
print("No user with e-mail {email}!".format(email=email)) | ||
else: | ||
self.users[email].read_book(book, rating) | ||
if rating != None: | ||
book.add_rating(rating) | ||
if book in self.books: | ||
self.books[book] += 1 | ||
else: | ||
self.books[book] = 1 | ||
|
||
def add_user(self, name, email, user_books=None): | ||
if email in self.users: | ||
print("Error: That user already exists.") | ||
else: | ||
user = User(name, email) | ||
self.users[email] = user | ||
if user_books != None: | ||
for book in user_books: | ||
self.add_book_to_user(book, email) | ||
|
||
def print_catalog(self): | ||
for book in self.books.keys(): | ||
print(book) | ||
|
||
def print_users(self): | ||
for user in self.users.values(): | ||
print(user) | ||
|
||
def get_most_read_book(self): | ||
return max(self.books, key=lambda key: self.books[key]) | ||
|
||
def highest_rated_book(self): | ||
highest_rated = None | ||
highest_rating = 0 | ||
for book in self.books.keys(): | ||
rating = book.get_average_rating() | ||
if rating > highest_rating: | ||
highest_rated = book | ||
highest_rating = rating | ||
return highest_rated | ||
|
||
def most_positive_user(self): | ||
positive_user = None | ||
highest_rating = 0 | ||
for user in self.users.values(): | ||
avg_user_rating = user.get_average_rating() | ||
if avg_user_rating > highest_rating: | ||
positive_user = user | ||
highest_rating = avg_user_rating | ||
return positive_user | ||
|
||
def get_n_most_read_books(self, n): | ||
sorted_by_value = sorted(self.books.items(), key=lambda kv: kv[1], reverse=True) | ||
return sorted_by_value[0:n] | ||
|
||
def get_n_most_prolific_readers(self, n): | ||
readers = [] | ||
for email in self.users: | ||
books_read = len(self.users[email].books) | ||
readers.append((books_read, email)) | ||
readers.sort(reverse=True) | ||
|
||
if n > len(readers): | ||
n = len(readers) | ||
|
||
result = [] | ||
for i in range(n): | ||
result.append(self.users[readers[i][1]]) | ||
return result | ||
|
||
def get_n_most_expensive_books(self, n): | ||
most_expensive_books = [] | ||
for book in self.books.keys(): | ||
most_expensive_books.append((book.price, book)) | ||
most_expensive_books.sort(reverse=True) | ||
|
||
if n > len(most_expensive_books): | ||
n = len(most_expensive_books) | ||
|
||
return most_expensive_books[0:n] | ||
|
||
def get_worth_of_user(self, user_email): | ||
total_worth = 0 | ||
user = self.users[user_email] | ||
|
||
for book in user.books: | ||
total_worth += book.price | ||
return "Total price of books owned by user {0}: ${1:.2f}".format(user_email, total_worth) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from TomeRater import * | ||
|
||
Tome_Rater = TomeRater() | ||
|
||
# Create some books: | ||
book1 = Tome_Rater.create_book("Society of Mind", 12345678, 12.00) | ||
novel1 = Tome_Rater.create_novel("Alice In Wonderland", "Lewis Carroll", 12345, 10.00) | ||
novel1.set_isbn(9781536831139) | ||
nonfiction1 = Tome_Rater.create_non_fiction("Automate the Boring Stuff", "Python", "beginner", 1929452, 25.00) | ||
nonfiction2 = Tome_Rater.create_non_fiction("Computing Machinery and Intelligence", "AI", "advanced", 11111938, 30.00) | ||
novel2 = Tome_Rater.create_novel("The Diamond Age", "Neal Stephenson", 10101010, 20.00) | ||
novel3 = Tome_Rater.create_novel("There Will Come Soft Rains", "Ray Bradbury", 10001000, 15.00) | ||
|
||
# Create users: | ||
Tome_Rater.add_user("Alan Turing", "[email protected]") | ||
Tome_Rater.add_user("David Marr", "[email protected]") | ||
|
||
# Add a user with three books already read: | ||
Tome_Rater.add_user("Marvin Minsky", "[email protected]", user_books=[book1, novel1, nonfiction1]) | ||
|
||
# Add books to a user one by one, with ratings: | ||
Tome_Rater.add_book_to_user(book1, "[email protected]", 1) | ||
Tome_Rater.add_book_to_user(novel1, "[email protected]", 3) | ||
Tome_Rater.add_book_to_user(nonfiction1, "[email protected]", 3) | ||
Tome_Rater.add_book_to_user(nonfiction2, "[email protected]", 4) | ||
Tome_Rater.add_book_to_user(novel3, "[email protected]", 1) | ||
|
||
Tome_Rater.add_book_to_user(novel2, "[email protected]", 2) | ||
Tome_Rater.add_book_to_user(novel3, "[email protected]", 2) | ||
Tome_Rater.add_book_to_user(novel3, "[email protected]", 4) | ||
|
||
|
||
# Uncomment these to test your functions: | ||
print("Catalog:") | ||
Tome_Rater.print_catalog() | ||
print("Users:") | ||
Tome_Rater.print_users() | ||
|
||
print("Most positive user:") | ||
print(Tome_Rater.most_positive_user()) | ||
print("Highest rated book:") | ||
print(Tome_Rater.highest_rated_book()) | ||
print("Most read book:") | ||
print(Tome_Rater.get_most_read_book()) | ||
|
||
# Add user with invalid e-mail address | ||
#Tome_Rater.add_user("Test User", "test@test") | ||
|
||
# Attempt to create a book object with an existing ISBN (should fail) | ||
#novel4 = Tome_Rater.create_novel("Through The Looking Glass", "Lewis Carroll", 12345678, 10.00) | ||
|
||
print(Tome_Rater) | ||
print() | ||
print(Tome_Rater.get_n_most_read_books(4)) | ||
print() | ||
print(Tome_Rater.get_n_most_prolific_readers(4)) | ||
print() | ||
print(Tome_Rater.get_n_most_expensive_books(3)) | ||
print() | ||
print(Tome_Rater.get_worth_of_user("[email protected]")) |