books

1.谁动了我的奶酪

2.傲慢与偏见

3.简爱

4.理智与情感

import user import book import csv import datetime from datetime import timedelta import typing class Loan: def __init__(self, user, book, borrow_str, due_str, return_str): self.user = user self.book = book self.borrow_date = parse_date(borrow_str) self.due_date = parse_date(due_str) self.return_date = parse_date(return_str) def calculate_fine(self): TODAY = datetime.datetime.strptime("15/09/2025", "%d/%m/%Y").date() if self.book.book_type == "online": return 0.0 if TODAY <= self.due_date: return 0.0 grace = {"Student": 0, "Staff": 2, "Others": 0}[self.user.role] effective_due = self.due_date + timedelta(days = grace) overdue_days = max(0, (TODAY - effective_due).days) rate = 0.50 if self.user.role in ['Student', 'Staff'] else 1.00 return overdue_days * rate def parse_date(date_str: str) -> typing.Optional[datetime.date]: if not date_str or date_str.strip() == "None": return None day, month, year = map(int, date_str.split('/')) return datetime.date(year, month, day) def load_users(file_path: str) -> dict: users = {} with open(file_path, newline='') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: user_id, password, name, role, department = row role = row[3].capitalize() if user_id.startswith('s'): u = user.Student(user_id, password, name, role, None) elif user_id.startswith('e'): u = user.Staff(user_id, password, name, role, department) else: role = "Others" u = user.Other(user_id, password, name, role, None) users[user_id] = u return users def load_books(file_path: str) -> dict: books = {} with open(file_path, newline='') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: book_id, book_type, copies, title, author, year, keywords = row b = book.Book(book_id, book_type, int(copies), title, author, int(year), keywords) books[book_id] = b b.loans = [] return books def load_loans(file_path: str, users: dict, books: dict): loans = [] with open(file_path, newline='') as csvfile: reader = csv.reader(csvfile) next(reader) for row in reader: user_id, book_id, borrow_date, due_date, return_date = row if user_id in users and book_id in books: loan = Loan(users[user_id], books[book_id], borrow_date, due_date, return_date) users[user_id].add_loan(loan) books[book_id].loans.append(loan) loans.append(loan) return loans def borrow_return_console(user, books, users): TODAY = datetime.datetime.strptime("15/09/2025", "%d/%m/%Y").date() while True: cmd = input("> ").strip() if cmd == "quit": return part = cmd.split(' ', 1) if len(part) < 2: continue action, query = part[0].lower(), part[1] if action == "borrow": matched_books = [] for b in books.values(): if query.lower() in b.title.lower() or query == b.book_id: matched_books.append(b) matched_books.sort(key=lambda x: x.book_id) if not matched_books: print(f"No books match '{query}'.") continue physical_match = [b for b in matched_books if b.book_type == "physical"] online_match = [b for b in matched_books if b.book_type == "online"] available_str = sum(b.available_copies() for b in physical_match) print(f"Found {len(matched_books)} book(s).") all_matches = physical_match + online_match all_matches.sort(key=lambda x: x.book_id) for b in all_matches: copies = f"Available copies: {available_str}/{b.total_copies}" if b.book_type == "physical" else "Available copies: 0/0" print(f"- {b.book_id} ({b.book_type}) '{b.title}' by {b.authors} ({b.year}). {copies}.") valid_ids = [b.book_id for b in all_matches] while True: borrowid = input(f"Confirm the Book ID you'd like to borrow: ").strip() if borrowid == "quit": break if borrowid not in valid_ids: continue book = books[borrowid] unpaid_fine = sum(loan.calculate_fine() for loan in user.get_active_loans()) if unpaid_fine > 0: print("Borrowing unavailable: unpaid fines. Review your loan details for more info.") break current_physical = sum(1 for loan in user.get_active_loans() if loan.book.book_type == "physical") if current_physical >= user.get_loan_policy()["quota"]: print("Borrowing unavailable: quota reached. Review your loan details for more info.") break if book.book_type == "physical" and book.available_copies() <= 0: print("No copies available.") break due_days = user.get_loan_policy()["days"] due_date = TODAY + timedelta(days = due_days) borrow_str = TODAY.strftime("%d/%m/%Y") due_str = due_date.strftime("%d/%m/%Y") return_str = "None" loan = Loan(user, book, borrow_str, due_str, return_str) user.loans.append(loan) book.loans.append(loan) print(f"You have borrowed '{book.title}' by {book.authors} ({book.year}). Due: {due_date.strftime('%d/%m/%Y')}.") break elif action == "return": borrowid = query.strip() if borrowid not in books: print("No loan record for {}.".format(borrowid)) continue book = books[borrowid] active_loans = [loan for loan in user.get_active_loans() if loan.book.book_id == borrowid] if not active_loans: print(f"No loan record for {borrowid}.") continue loan_to_return = min(active_loans, key=lambda x: x.due_date) user.loans.remove(loan_to_return) return_date = TODAY fine_amount = 0.0 overdue_days = 0 if book.book_type == "physical" and return_date > loan_to_return.due_date: grace = {"Student": 0, "Staff": 2, "Others": 0}[user.role] effective_due = loan_to_return.due_date + timedelta(days = grace) overdue_days = max(0, (TODAY - effective_due).days) rate = 0.50 if user.role in ['Student', 'Staff'] else 1.00 fine_amount = overdue_days * rate status = f"Returned '{book.title}' by {book.authors} ({book.year})." if overdue_days > 0: status += f" Overdue by {overdue_days} day(s). Fine: $ {fine_amount:.2f}" print(status) elif action == "renew": borrowid = query.strip() due_days = user.get_loan_policy()["days"] due_date = TODAY + timedelta(days = due_days) for loan in user.get_active_loans(): if int(loan.calculate_fine()) > 0: print("Renewal denied: You have unpaid fines") continue if TODAY > due_date: print("Renewal denied: This book is already overdue") book = books[borrowid] active_loans = [loan for loan in user.get_active_loans() if loan.book.book_id == borrowid] loan_to_renew = min(active_loans, key=lambda x: x.due_date) if loan_to_renew.renewed: print("Renewal unavailable: Each book can only be renewed once.") continue loan_to_renew.due_date = loan_to_renew.due_date + timedelta(days=5) loan_to_renew.renewed = True print(f"Renew '{book.title}' by {book.authors} (book.year) successfully. New due date: {loan_to_renew.due_date.strftime('%d/%m/%Y')}") else: continue def search_by_keywords(books): keywords = input("Enter search keywords (separated by comma): ").strip().lower().split(',') if not keywords or keywords[0] == '': print("Found 0 book(s).") return result = [] for b in book.values(): matched = sum(1 for keyword in keywords if keywords in book.title.lower() or keywords in ' '.join(book.keywords).lower()) if matched > 0: result.append(book, matched) result.sort(key=lambda x: (-x[1], -x[0].year, x[0].book_id)) print(f"Found {len(result)} book(s).") for i, (book, _) in enumerate(result): print(f"{i+1}. {book.book_id} '{book.title}' by {book.authors} ({book.year}).") def manage_library(books, existing_keywords): while True: cmd = input("> ").strip() if cmd == "quit": break elif cmd == "report": total_user = len(users) students = sum(1 for u in users.values() if u.user_id.startswith('s')) staffs = sum(1 for u in users.values() if u.user_id.startswith('e')) others = sum(1 for u in users.values() if u.user_id.startswith('o')) total_books = len(books) physical_books = sum(1 for b in books.values() if b.book_type == "physical") available_physical = sum(1 for b in books.values() if b.book_type == "physical" and b.is_available()) online_books = sum(1 for b in books.values() if b.book_type == "online") print("Library report") print(f"- {total_user} users, including {students} student(s), {staffs} staff, and {others} others.") print(f"- {total_books} books, including {physical_books} physical book(s) ({available_physical} currently available) and {online_books} online book(s).") elif cmd.startswith("add "): book_type = cmd.split(" ")[1] if book_type not in ["physical", "online"]: print("Invalid cmd.") continue title = input("Title: ") authors = input("Authors: ") year = input("Year: ") if book_type == "physical": copies = input("Copies: ") else: copies = 0 all_keywords = set() for b in books.value(): all_keywords.update(books.keywords) detected_keywords = [word for word in title.lower().split() if word in all_keywords] detected_keywords.sort() keywords_str = ":".join(detected_keywords) if book_type == "physical": physical_ids = [int(book.book_id[1:]) for book in books.values() if book.book_id.startswith('P')] new_id = f"P{str(max(physical_ids) + 1)}" else: online_ids = [int(book.book_id[1:]) for book in books.values() if book.book_id.startswith('E')] new_id = f"E{str(max(online_ids) + 1)}" new_book = book(new_id, book_type, copies, title, authors, year, keywords_str) book[new_id] = new_book print(f"Detected keywords: {keywords_str}") print(f"Adding {new_id} '{title}' by {authors} ({year}).") def main(user_file: str, book_file:str, loan_file:str) -> None: """ This is the entry of your program. Please DO NOT modify this function signature, i.e. function name, parameters Parameteres: - user_file (str): path the `users.csv` which stores user information - book_file (str): path the `books.csv` which stores book information - loan_file (str): path the `loans.csv` which stores loan information """ # Your implemetation goes here users = load_users(user_file) books = load_books(book_file) load_loans(loan_file, users, books) while True: print("Welcome to Library") user_input = input("Login as: ").strip() if user_input == "quit": print("Goodbye!") return else: password = input("Password: ").strip() if user_input not in users or users[user_input].password != password: print("Invalid credentials. 2 attempt(s) remaining.") user_input = input("Login as: ").strip() password = input("Password: ").strip() if user_input not in users or users[user_input].password != password: print("Invalid credentials. 1 attempt(s) remaining.") user_input = input("Login as: ").strip() password = input("Password: ").strip() if user_input not in users or users[user_input].password != password: print("Sorry you're out of attempts. Please contact your librarian for assistance.") continue current_user = users[user_input] print(f"Logged in as {current_user.name} ({current_user.role})") while True: menu = [ "My Library Account", "0. Quit", "1. Log out", "2. View account policies", "3. View my loans", "4. Borrow and Return", "5. Search by Keywords" ] if current_user.is_library_staff(): menu.append("6. Manage Library") print("=" * 34) for item in menu: print(item) print("=" * 34) while True: try: choice = input("Enter your choice: ").strip() if not choice.isdigit() or choice not in ['0', '1', '2', '3', '4', '5', '6']: continue choice = int(choice) break except: continue if choice == 0: print("Goodbye!") return elif choice == 1: break elif choice == 2: policy = current_user.get_loan_policy() active_loans = current_user.get_active_loans() num_loans = len(active_loans) phys, online = current_user.get_physical_online_count() total_fine = sum(loan.calculate_fine() for loan in active_loans) print(f"{current_user.role} {current_user.name}. Policies: maximum of {policy['days']} days, {policy['quota']} items. Current loans: {num_loans} ({phys} physical / {online} online). Fines: $ {total_fine:.2f}") elif choice == 3: active_loans = sorted(current_user.get_active_loans(), key=lambda x: x.due_date) count = len(active_loans) print(f"You are currently have {count} loan(s).") for i, loan in enumerate(active_loans, 1): print(f"{i}. {loan.book.book_id} '{loan.book.title}' by {loan.book.authors} ({loan.book.year}). Due date: {loan.due_date.strftime('%d/%m/%Y')}.") elif choice == 4: borrow_return_console(current_user, books, users) elif choice == 5: total_user = len(users) students = sum(1 for u in users.values() if u.user_id.startswith('s')) staffs = sum(1 for u in users.values() if u.user_id.startswith('e')) others = sum(1 for u in users.values() if u.user_id.startswith('o')) total_books = len(books) physical_books = sum(1 for b in books.values() if b.book_type == "physical") available_physical = sum(1 for b in books.values() if b.book_type == "physical" and b.is_available()) online_books = sum(1 for b in books.values() if b.book_type == "online") print("Library report") print(f"- {total_user} users, including {students} student(s), {staffs} staff, and {others} others.") print(f"- {total_books} books, including {physical_books} physical book(s) ({available_physical} currently available) and {online_books} online book(s).") else: continue if __name__ == "__main__": main('data/users.csv', 'data/books.csv', 'data/loans.csv')
最新发布
10-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值