面向对象地址簿程序删除条目异常问题求助
问题分析
你遇到的核心问题是显示的条目是排序后的,但删除操作基于原列表的顺序,两者索引不匹配,导致删除了错误的元素;同时删除方法的异常处理逻辑存在漏洞,没有正确检查索引有效性。
举个例子:原列表顺序是[Joe J, Eric, Joe S],但界面显示的是排序后的[Eric, Joe J, Joe S],你输入1想删Eric,实际删除的是原列表第0位的Joe J,再次显示时排序后的列表就只剩Eric和Joe S,和预期完全不符。
修正后的完整代码
import pickle import os.path # Constants SAVE_FILE_NAME = 'address_book_contents.pickle' INSTRUCTIONS = '''Address Book Application Press: a to add an entry r to remove an entry d to display a list of all entries in summary form s to display a list of all entries sorted alphabetically in summary form i to print these instructions again q to quit ''' CONFIRM_QUIT_MESSAGE = 'Are you sure you want to quit (Y/n)? ' SUMMARY_TEMPLATE = "%s %s DOB: %s email: %s" ### Classes Section class AddressBook (object): ''' This class holds and manages a list of my contacts ''' def __init__ (self): ''' Set people attribute to an empty list ''' self.people = [] def add_entry (self, new_entry): ''' Adds a new entry to the list of people in the address book. The new_entry is an instance of the AddressEntry class''' self.people.append(new_entry) def remove_entry(self, original_index): '''Removes an entry from the list using its original index in self.people''' try: del self.people[original_index] return None except IndexError: return "INVALID ENTRY! Invalid entry index" def is_list_empty(self): '''Returns True if the address book has no entries, False otherwise''' return len(self.people) == 0 def save(self): with open(SAVE_FILE_NAME, 'wb') as file_object: pickle.dump(self, file_object) class AddressEntry (object): ''' This class has one instance for each person's details ''' def __init__ (self, first_name=None, last_name=None, email=None, DOB=None): '''Initializes attributs f_name, l_name, email, and birthday. Each arg is a string. Birthday should be a string in the format MM DD, YYYY ''' self.first_name = first_name self.last_name = last_name self.email = email self.DOB = DOB def __repr__ (self): '''Given an AddressEntry object self return a readable string representation ''' return f"AddressEntry(first_name='{self.first_name}', last_name='{self.last_name}', email='{self.email}', DOB='{self.DOB}')" class Controller(object): def __init__(self): self.address_book = self.load() if self.address_book is None: self.address_book = AddressBook() self.run_interface() def load(self): if os.path.exists(SAVE_FILE_NAME): with open(SAVE_FILE_NAME, 'rb') as file_object: address_book = pickle.load(file_object) return address_book else: return None def run_interface(self): print(INSTRUCTIONS) while True: command = input('What would you like to do? (press i to see all the options again) ') if command == 'a': self.add_entry() elif command == 'r': self.remove_entry() elif command == 'd': print("Displaying summaries of all people stored in the address book") self.display_summaries() elif command == 's': self.sort_entries() elif command == 'i': print(INSTRUCTIONS) elif command == 'q': user_quit = input(CONFIRM_QUIT_MESSAGE) if user_quit.lower() == 'y': print('\nSaving...') self.address_book.save() print("\nThank you for using my address book application; come again soon!") break elif user_quit.lower() == 'n': continue else: print(f"I don't recognize that instruction ({command}) ") def add_entry(self): print("Adding a new person to the address book") print("What is the person's: ") first_name = input("First Name? ") if first_name == 'q': print('Not Adding') return last_name = input("Last Name? ") if last_name == 'q': print('Not Adding') return email = input("Email Address? (if they don't have one, just enter None) ") if email == 'q': print('Not Adding') return DOB = input("Date of Birth? (Enter in the format MM DD, YYYY) ") if DOB == 'q': print('Not Adding') return new_entry = AddressEntry(first_name, last_name, email, DOB) self.address_book.add_entry(new_entry) print(f"Added address entry for {first_name} {last_name}\n") def display_summaries(self, return_entries=False): if self.address_book.is_list_empty(): print("Cannot display summaries because the address book is empty") return [] if return_entries else None # 存储排序用值、显示用值和原列表索引 indexed_entries = [] for idx, entry in enumerate(self.address_book.people): sort_values = (entry.first_name, entry.last_name) display_values = (entry.first_name, entry.last_name, entry.DOB, entry.email) indexed_entries.append( (sort_values, display_values, idx) ) # 按姓名排序 indexed_entries.sort(key=lambda x: x[0]) # 显示条目 for display_idx, (_, display_vals, _) in enumerate(indexed_entries, 1): entry_str = SUMMARY_TEMPLATE % display_vals print(f"{display_idx}: {entry_str}") # 如果需要返回索引信息(供删除功能使用) if return_entries: return [ (display_vals, idx) for (_, display_vals, idx) in indexed_entries ] return None def remove_entry(self): print("Removing a person from the address book\n") if self.address_book.is_list_empty(): print("There are no entries to remove from the address book") return # 获取带原索引的排序后条目 indexed_entries = self.display_summaries(return_entries=True) while True: user_input = input("\nEnter the number of the entry you would like to remove: ") if user_input == 'q': print("Exiting remove entry") return try: display_idx = int(user_input) - 1 # 转成显示列表的0-based索引 if display_idx < 0 or display_idx >= len(indexed_entries): print(f"INVALID ENTRY! There is no entry number {user_input}") continue # 获取原列表中的真实索引 original_idx = indexed_entries[display_idx][1] # 删除条目 result = self.address_book.remove_entry(original_idx) if result: print(result) else: print(f"Entry number {user_input} has been removed") break except ValueError: print("INVALID ENTRY! Please enter an integer number instead of a character") def sort_entries(self): print("Sorting Entries") if self.address_book.is_list_empty(): print("Cannot sort because the address book is empty") return # 复用display_summaries的排序和显示逻辑 self.display_summaries() ### Main section controller = Controller()
关键修改说明
匹配显示与删除的索引:
- 修改
display_summaries方法,让它在显示排序后条目的同时,记录每个条目在原列表中的真实索引。 - 删除时根据用户输入的显示编号,找到对应条目在原列表中的位置,确保删除的是用户看到的条目。
- 修改
修正异常处理:
- 移除了原删除方法中无效的
IndexError捕获,改为在控制器层先验证输入的编号是否合法(是否为整数、是否在条目范围内),错误提示更精准。
- 移除了原删除方法中无效的
优化空列表判断:
- 重写
is_list_empty方法返回布尔值,让空列表判断逻辑更直观易读。
- 重写
修复语法错误:
- 修正了
AddressEntry.__repr__中的多行字符串拼接问题,改用f-string简化代码。
- 修正了
现在测试代码,删除操作会准确对应界面显示的条目,之后的列表展示也会符合你的预期。
内容的提问来源于stack exchange,提问作者user32453215
相关产品推荐
相关产品推荐

