前言
从文章 python学习——【第十七弹】 开始,我们开始进入python巩固篇,利用所学基础知识来做一个简单的 学生信息管理系统,温故而知新。
上篇文章 python学习——【第十八弹】我们编写了学生信息管理系统的查询功能,这篇文章实现学生信息的删除功能。
需求分析
之前的学习我们了解了python中对文件的读写操作,那么我们可以利用”写“操作的追加覆盖性,实现用于存放的学生信息的文件 ”students.txt"的删除更新。
用户可以选择按照学生ID\姓名两种删除方式,删除指定学生;
如果没有查找到指定学生信息给予用户反馈,查到则告知用户学生信息已删除;
当用户执行完毕一次删除操作后,询问用户是否再次进行删除操作,如果是则继续执行,反之退出。
思路整理
获取用户的删除选择方式,用到input()函数;
判断学生信息是否删除需要用if..else...判断语句;
执行删除操作的 继续/退出需要用到 while循环语句;
将整个删除功能放到一个函数中,用户使用该该模块直接在主函数中调用即可。
学生信息删除函数delete()的编写
首先我们需要引入 os模块,利用os.path.exists()判断存储学生信息的文件是否存在
import os
filename='../students.txt'
然后开始delete()函数的编写,结合前面的思路,我们将大体框架写出来,这里我们以用户选择ID为例
import os
filename = '../students.txt'
def delete():
while True:
student_id = input('请输入学生ID:')
if student_id !='':
if os.path.exists('filename'):
# 使用with语句执行“读”操作,将所读取的学生信息放到一个列表 student_befor中
pass
else:
# 如果存放学生信息的文件不存在,就返回一个空列表 student_befor=[]
pass
# 编写一个删除标记,如果学生信息删除就为True,反之为False,默认为False
flag = False
#开始执行“写”操作,目的是将students.txt中和用户输入的学生ID不相符的学生信息再写入 students.txt中,完成覆盖更新
pass
if flag:
print('学生信息已删除')
else:
print('抱歉,没有查找到该学生信息')
#询问用户是否继续进行删除操作
ans = input('请问你还需要继续删除吗?(y/n)')
if ans == 'y':
continue
else:
break
读取学生信息
if student_id!='':
if os.path.exists(filename):
with open(filename,'r',encoding='utf-8')as file:
student_befor=file.readlines()
else:
student_befor=[]
print(student_befor)
print(type(student_befor))
我们看写此时student_befor列表中的信息存放情况
将字符串类型的学生信息转换成字典,以便进行键值匹配
if student_befor:
d={} #定义一个空字典
for item in student_befor: #遍历student_befor,遍历返回的结果是字符串
d=dict(eval(item)) #遍历得到的字符串转换成字典
print('这是转化而来的字典:',d)
根据用户输入的学生ID匹配相关信息
if d['id']!=student_id:#如果字典中的元素的键值可以不和用户输入的学生ID相同就写入students.txt文件中;此时students.txt文件中不含有用户输入的ID所对应的学生信息
w_file.write(str(d)+'\n')
print(d)#查看删除指定学生信息后的students.txt
else:
print('已删除')
最终代码
import os
filename='../students.txt'
def delete():
while True:
student_id=input('请输入您要删除的学生的ID:')
#如果输入学生的ID,并且存储学生信息的文件存在话,就读取文件中的学生信息,并以列表的形式返回。
if student_id!='':
if os.path.exists(filename):
with open(filename,'r',encoding='utf-8')as file:
student_befor=file.readlines()
else:
student_befor=[]
#标记是否完成删除操作
flag=False #默认值False,没有删除
#如果student_befor返回的是True,就代表列表中有内容;空列表布尔值是False
if student_befor:
with open(filename,'w',encoding='utf-8')as w_file:
d={} #定义一个空字典
for item in student_befor:
d=dict(eval(item)) #将字符串转换为字典
#如果需要删除的id字符串和已有的学生id不相等的话,就将该信息写入students.txt中
if d['id']!=student_id:
w_file.write(str(d)+'\n')
else:
flag=True #表示已删除
if flag:
print(f'ID为{student_id}的学生信息已被删除')
else:
print(f'抱歉,没有找到ID为{student_id}的学生信息')
#如果学生信息没有录入的话,就打印出'无学生信息',并退出删除操作
else:
print('无学生信息')
break
answer=input('是否要继续删除?y/n\n')
if answer=='y':
continue
else:
break
按学生姓名修改的思路同上,这里就不做赘述了。
问题反馈
在完成“删除方式的选择”的功能时,出现了一些报错,这里记录一下报错原因,加以修改
UnboundLocalError
当我想让用户选择按照学生ID\姓名进行删除时,按照原有思路直接用 input()函数来收集用户的选择,然后进行键值匹配,发现运行后出现 UnboundLocalError 错误:
报错原因很明显,是由于变量的作用域导致的,原因如下
1. 如果在函数内部尝试给一个局部变量赋值,但该变量未被定义,则会发生UnboundLocalError。
2. 如果在函数内部尝试修改一个全局变量的值,但该变量未被声明为global,则会发生
UnboundLocalError。
3. 如果在函数内部尝试访问一个局部变量,但该变量还未被赋值,则会发生UnboundLocalError。
4. 如果在函数内部使用了与全局变量同名的变量,则会发生UnboundLocalError。
5. 如果在函数内部定义了一个和全局变量同名的变量,则必须使用global关键字声明该变量为全局变量,否则会发生UnboundLocalError。
我们看下代码:
在 delete()函数中我们定义了两个变量 student_id student_name,如果用户选择其中一种方式(学生ID或学生姓名)的话,那么另一个变量就相当于没有被声明,此时我们就需要在用户做出选择之前就在函数内部对这两个变量做出声明,即:
如果将其放到函数外,函数内部需要使用global声明
答非所问
先看运行结果,大家能看出哪有问题吗?没错,我明明输入的是n(结束删除操作),可是系统为什么还要我继续选择删除方式呢?经过断点调试,发现我红色框选中的if...else语句在执行中无论我输入什么都会自动忽略else的执行。
在网上查阅资料后发现,这是由于python中if语句中的大小写不敏感造成的
在Python中,'Y'和'y'都被视为True值,所以在if语句中,无论用户输入的是大写还是小写,'Y'或'y'都会被视为True。
解决方法如下:
1. if choice in ["Y","y"]:
# do something
else:
# do something else
2. if choice == 'y' or choice == 'Y':
# do something
else:
#do something else
3. #可以将用户输入转换为小写或大写字母并将其与小/大写的“y”进行比较,如下所示:
#把字符串所有字母都转换成小写形式,并返回转换后的字符串。
if choice.lower() == 'y':
# do something
else:
# do something else
4. #把字符串所有字母都转换成大写形式,并返回转换后的字符串。
if choice.upper() == 'Y':
# do something
else:
# do something else
每篇一语
人可以休息,但不能止息。当你停下脚步的时候,别忘了别人还在奔跑。
如有不足,感谢指正!