当我尝试从我的 CSV 文件中删除一行时,它会删除其余所有内容,然后将该行横向移动,并将字符分成单独的列。我不知道发生了什么。上面的图片显示了我尝试删除 CSV 文件的前后对比。我不知道发生了什么,这太奇怪了。这是我的代码,问题出在第 95 行:
import csv
import sys
FILENAME = "guests.csv"
def exit_program():
print("Terminating program.")
sys.exit()
def read_guests():
try:
guests = []
with open(FILENAME, newline="") as file:
reader = csv.reader(file)
for row in reader:
guests.append(row)
return guests
except FileNotFoundError as e:
## print(f"Could not find {FILENAME} file.")
## exit_program()
return guests
except Exception as e:
print(type(e), e)
exit_program()
def write_guests(guests):
try:
with open(FILENAME, "w", newline="") as file:
## raise BlockingIOError("Error raised for testing.")
writer = csv.writer(file)
writer.writerows(guests)
except OSError as e:
print(type(e), e)
exit_program()
except Exception as e:
print(type(e), e)
exit_program()
def list_guests(guests):
number_of_guests = 0
number_of_members = 0
total_fee = 0
for i, guests in enumerate(guests, start=1):
print(f"{i}. Name: {guests[0]} {guests[1]}\n Meal: {guests[2]} \n Guest Type: {guests[3]} \n Amount due: ${guests[4]}")
if guests[3] == "guest":
number_of_guests +=1
if guests[3] == "member":
number_of_members +=1
total_fee += 22
print("Number of members: " +str(number_of_members))
print("Number of guests: " +str(number_of_guests))
print("Total fee paid by all attendees: " +str(total_fee))
print()
def add_guests(guests):
fname = input("First name: ")
lname = input("Last name: ")
while True:
try:
meal = str(input("Meal(chicken, vegetarian, or beef): "))
except ValueError:
print("Please enter a meal. Please try again.")
continue
if meal == "beef" :
break
if meal == "chicken" :
break
if meal == "vegetarian" :
break
else:
print("Please enter a meal:(chicken, vegetarian, or beef)")
while True:
attendee_type = input("Are you a 'member' or 'guest'?")
if attendee_type == "member" :
break
if attendee_type == "guest" :
break
else:
print("Please enter either 'member' or 'guest': ")
fee = 22
guest = [fname, lname, meal, attendee_type, fee]
guests.append(guest)
write_guests(guests)
print(f"{fname} was added.\n")
def delete_guest(guests):
name = input("Enter the guest's first name: ")
for i, guests in enumerate(guests, start=1):
if name == guests[0]:
del guests[i]
write_guests(guests)
print(f"{name} removed from catalog.")
print("")
break
print(f"{name} doesn't exist in the list.")
def menu_report(guests):
number_of_beef = 0
number_of_chicken = 0
number_of_vegetarian = 0
for i, guests in enumerate(guests, start=1):
if guests[2] == "beef":
number_of_beef +=1
if guests[2] == "chicken":
number_of_chicken +=1
if guests[2] == "vegetarian":
number_of_vegetarian +=1
print("Number of Chicken entrees: " +str(number_of_chicken))
print("Number of Beef entrees: " +str(number_of_beef))
print("Number of vegetarian Meals: " +str(number_of_vegetarian))
print()
def display_menu():
print("COMMAND MENU")
print("list - List all guests")
print("add - Add a guest")
print("del - Delete a guest")
print("menu - Report menu items")
print("exit - Exit program")
print()
def main():
print("The Guests List program")
print("")
guests = read_guests()
while True:
display_menu()
command = input("Command: ")
if command.lower() == "list":
list_guests(guests)
elif command.lower() == "add":
add_guests(guests)
elif command.lower() == "del":
delete_guest(guests)
elif command.lower() == "menu":
menu_report(guests)
elif command.lower() == "exit":
break
else:
print("Not a valid command. Please try again.\n")
print("Bye!")
quit()
if __name__ == "__main__":
main()
这是明天截止的作业!arg!
我以为它会删除该行,但它只保存了该行,并将该行一列中的每个条目放入其所在行。原始行中的每个字符现在都被分成它自己的列。
在你的 for 循环中,你重复使用了变量名 guests,它与所有客人的列表同名。
这会覆盖循环中的列表,并导致意外行为。
循环中的 guests 指的是单个 guest 行,而不是完整列表。当您尝试 del guests[i] 时,实际上是从单个行中删除索引(如果索引损坏,甚至会删除一个字符串)。因此,当您稍后调用 write_guests(guests) 时,它会将无效数据写入文件,从而导致您描述的“文本横向移动”问题。您可以通过将循环变量名称更改为其他名称(例如“guest”)来解决这个问题。
这是一个使用 guest 作为命名循环变量的修复版本。
避免遮蔽
在适当的情况下使用单数和复数标识符。通常的用法是
for x in xs:
你写道:
你想写的是
for i, guest in ...
当测试
name
相等性时,您想要引用guest[0]
行的第一列。遗憾的是,新的
guests
局部变量遮挡了原始guests
参数。因此,该参数在循环体内不再可访问。循环外的变异
match_index = i
我建议在循环内有条件地分配,然后在循环完成del guests[match_index]
后发出。for
此外,遗憾的是该程序没有验证每个客人的姓名是否唯一。
如果您希望根据非唯一属性进行过滤,例如删除包含“牛肉”的客人,可以考虑构建一个新的过滤列表并返回该列表。这样可以避免跳过可能匹配的行。
首先规范化
最好立即将其小写。
.lower()
然后,您可以在后续的调度测试中节省大量分散注意力的呼叫。