# coding:utf-8
# @Author:dx
# @Time:2023-4-20
# @File:学生信息管理系统(面向对象).py
import pickle
import os
import logging
"""
学生信息管理系统
1:将学生信息存入一个pickle文件中,添加读与写pickle的函数
2:我们要将用户添加修改和删除的行为记录到日志中,添加与修改都用info代表
而delete将要用warn警告来提示
"""
print('欢迎使用学生信息管理系统~>_<~')
# 创建一个自定义的异常类,用于得知输入的服务序号是否超出了范围
class OrderNumberError(Exception):
def __init__(self, message):
self.message = message
# 创建一个自定义的异常类,用于判断用户是否输入了参数
class NotArgError(Exception):
def __init__(self, message):
self.message = message
# 判断地址是否有效
class MissPathError(Exception):
def __init__(self, message):
self.message = message
class FormatError(Exception):
def __init__(self, message):
self.message = message
class StudentsInfo(object):
"""类中的函数没有先后顺序,无论定义在哪里都可以获取到"""
# 将字典对象传入类中
def __init__(self, students_path, log_path):
self.students_path = students_path
self.log_path = log_path
self.__log()
self.__init_path()
self.__read()
def __log(self):
if os.path.exists(self.log_path):
mode = 'a'
else:
mode = 'w'
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s-%(filename)s-%(lineno)d-%(levelname)s-%(message)s',
filename=self.log_path,
filemode=mode
)
self.log = logging
def __init_path(self):
if not os.path.exists(self.students_path):
raise MissPathError('没有相关的地址文件')
if not os.path.isfile(self.students_path):
raise TypeError('当前的students_path不是一个文件')
if not self.students_path.endswith('.pickle'):
raise FormatError('当前不是一个pickle文件')
def __read(self):
with open(self.students_path, 'rb') as f:
try:
data = f.read()
except FormatError:
# 若打开的是一个空文件,则在文件中加入一个‘{}’,用来反序列化后被识别为一个字典
f.write(pickle.dumps('{}'))
self.students = pickle.loads(data)
def __save(self):
with open(self.students_path, 'wb') as f:
pickle_data = pickle.dumps(self.students)
f.write(pickle_data)
self.__read() # 用于保存之后拿到最新的用户数据
# 按学号查找学生信息
def get_by_id(self, students_id):
stu_data = self.students.get(students_id)
return '学号{},姓名{},年龄{},班级{},性别{}'.format(students_id, stu_data['name'], stu_data['age'], stu_data['class_number'], stu_data['sex'])
# 获取所有的学生信息5
def get_all(self):
for _id, value in self.students.items():
print('学号{},姓名{},年龄{},班级{},性别{}'.format(_id, value['name'], value['age'], value['class_number'], value['sex']))
return self.students
# 检查学生信息是否正确
@staticmethod
def check_user_info(**kwargs):
assert len(kwargs) == 4, '参数必须是四个'
if 'name' not in kwargs:
raise NotArgError('缺少学生姓名参数')
if 'age' not in kwargs:
raise NotArgError('缺少学生年龄参数')
if 'class_number' not in kwargs:
raise NotArgError('缺少学生班级参数')
if 'sex' not in kwargs:
raise NotArgError('缺少学生性别参数')
name_value = kwargs['name']
age_value = kwargs['age']
class_number_value = kwargs['class_number']
sex_value = kwargs['sex']
if not isinstance(name_value, str):
raise TypeError('name应该是字符串类型')
if not isinstance(age_value, int):
raise TypeError('age应该是整数类型')
if not isinstance(class_number_value, int):
raise TypeError('class_number应该是整数类型')
if not isinstance(sex_value, str):
raise TypeError('sex应该是字符串类型')
# 添加学生(单个)
def add(self, **student):
try:
self.check_user_info(**student)
except Exception as e:
raise e
self.__add(**student)
self.__save()
self.log.info('学生%s被注册' % student['name'])
# 添加成员(批量)
def adds(self, new_students):
for student in new_students:
try:
self.check_user_info(**student)
except Exception as e:
print(e, student.get('name'))
continue
self.__add(**student)
self.log.info('学生%s被注册' % student['name'])
self.__save()
# 用于将学号和新添加的学生成员绑定传入字典中
def __add(self, **student):
try:
new_id = max(self.students) + 1
self.students[new_id] = student
except ValueError:
new_id = 1
self.students[new_id] = student
# 用于删除单个成员
def delete(self, students_id):
if students_id not in self.students:
print('{}不存在'.format(students_id))
else:
deleted_students = self.students.pop(students_id)
print('学号为{}, 姓名为{}的学生已删除'.format(students_id, deleted_students['name']))
self.log.warning('学号为{}, 姓名为{}的学生已删除'.format(students_id, deleted_students['name']))
self.__save()
# 批量删除成员
def deletes(self, ids):
for student in ids:
self.log.warning('学号为{}, 姓名为{}的学生已删除'.format(student, self.students[student]['name']))
self.delete(student)
self.__save()
# 修改单个成员
def update(self, students_id, **kwargs):
if students_id not in self.students:
print('不存在这个学号')
return
try:
self.check_user_info(**kwargs)
except (NotArgError, TypeError) as e:
raise e
self.students[students_id] = kwargs
self.__save()
print('学生信息更新完毕!')
# 批量修改成员
def updates(self, update_students):
for student in update_students:
try:
_id = list(student.keys())[0]
except IndexError as e:
print(e)
continue
user_info = student[_id]
if _id not in self.students:
print(f'{_id}学号不存在')
continue
try:
self.check_user_info(**user_info)
except Exception as e:
print(e)
continue
"""
if check != True` 和 `if not check` 在大多数情况下是等价的,都是检查`check`是否为False。
但是这两个表达式在处理某些特定数据类型时可能会出现不同的行为。
如果`check`是一个自定义类的实例,那么 `check != True` 可能会调用`__ne__`方法(与`__eq__`相对),而 `not check`
则会调用`__bool__`或`__len__`方法来确定对象的“真值”(truth value)。因此,这两个表达式在这种情况下可能会产生不同的结果。
另外,如果 `check` 是一个可调用对象,例如一个函数或一个lambda表达式,那么 `not check` 会尝试调用它并检查结果是否为False,
而 `check != True` 则会检查 `check` 是否返回`True`或`False`。
总之,对于大多数数据类型,这两个表达式是等价的,但在某些特定情况下,它们可能会产生不同的结果。
"""
self.students[_id] = user_info
print('学生信息更新完毕!')
self.__save()
# 用于模糊匹配成员
def search(self, **kwargs):
"""
self.students = {1: {'name': '小舒', 'age': 18, 'class_number': 6, 'sex': 'famale'},
2: {'name': 'xiaoshu', 'age': 18, 'class_number': 2, 'sex': 'famale'},
3: {'name': 'xiaoding', 'age': 18, 'class_number': 5, 'sex': 'famale'},
4: {'name': 'xiaozhao', 'age': 19, 'class_number': 4, 'sex': 'male'}}
"""
datas = self.students # 创建一个指向学生信息的变量
result = []
compare = []
if sum(i is not None for i in list(kwargs.values())) != 0: # 判断user输入的信息是否全为空
pass
else:
raise NotArgError('没有发现搜索的关键词!')
for key in datas:
value = (self.students[key])
number = 0 # 用于存储查找到的用户的优先值,符合的信息项越多对应的优先值也就越高,后面会根据这个优先值,来把查找到的学生信息进行排序
if kwargs['name']: # 判断用户是否输入了姓名
if kwargs['name'] in str(value['name']):
number += 1 # 优先值+1
else:
continue
if kwargs['age']: # 判断用户是否输入了年龄
if str(kwargs['age']) in str(value['age']):
number += 1 # 优先值+1
else:
continue
if kwargs['class_number']: # 判断用户是否输入了班级
if kwargs['class_number'] in str(value['class_number']):
number += 1 # 优先值+1
else:
continue
if kwargs['sex']: # 判断用户是否输入了性别
if kwargs['sex'] in str(value['sex']):
number += 1 # 优先值+1
else:
continue
if number == 0:
continue
compare.append(number)
compare.sort(reverse=True)
result.insert(compare.index(number), {key: value}) # 会按照对应的信息个数从大到小进行排序
if not result:
print('未搜索到相关信息,或相关信息不符合')
return result
@staticmethod
def set_info():
print('请输入要查找、设置或更改后的学生信息:')
name1 = input('请输入学生姓名:')
age1 = int(input('请输入学生年龄:'))
class_number1 = int(input('请输入学生班级:'))
sex1 = input('请输入学生性别(male/famale):')
return dict(name=name1, age=age1, class_number=class_number1, sex=sex1)
# 用户选择的服务
def server(self):
n = True
while n:
print('==' * 20)
print('请选择服务:')
print('1.查看所有学生信息')
print('2.添加学生信息')
print('3.批量添加学生信息')
print('4.修改学生信息')
print('5.批量修改学生信息')
print('6.删除学生信息')
print('7.批量删除学生信息')
print('8.模糊查找学生信息')
print('9.按学号查找学生信息')
print('10.退出学生信息管理系统')
try:
choose = int(input('请输入服务序号:'))
if choose > 10:
raise OrderNumberError('服务序号不存在')
try:
if choose == 1:
self.get_all()
print('==' * 20)
except AttributeError:
print('当前库中无成员~')
if choose == 2:
ii = self.set_info() # ii == input_info代表输入的信息
self.add(**ii)
print('添加成功~,添加的学生信息如下:')
print(f'学号{max(self.students)}:{self.students[max(self.students)]}')
print('==' * 20)
if choose == 3:
result = []
condition = True
while condition:
infos = self.set_info()
result.append(infos)
choose_exit = input('是否继续添加?y/n:').lower()
if choose_exit == 'y':
continue
elif choose_exit == 'n':
self.adds(result)
print('添加成功!添加的全部信息如下~:')
for i in result:
# range 用于绑定学号与学生
for items in self.students:
if self.students[items] == i:
print(f'学号:{items}: {i}')
while True:
sure = input('以上信息是否有误?(y/n):').lower()
if sure == 'y':
print('即将进入修改界面~')
frequency = 0
while frequency <= 3:
try:
students_id = int(input('请输入所要更改学生的学号:'))
print('设置学生信息:')
ii1 = self.set_info() # ii == input_info代表输入的信息
self.update(students_id, **ii1)
except ValueError:
print(f'请输入正确格式的学号!(输错3次即强制退出,目前{frequency}次)')
frequency += 1
print('==' * 20)
elif sure == 'n':
condition = False
break
else:
print('error!!!请输入y/n:')
else:
print('error!!!请输入y/n:')
if choose == 4:
id_number = int(input('请输入已存在的学号:'))
print('学号-{{{}}}-,对应的学生信息如下:\n{}'.format(id_number, self.students[id_number]))
print('请选择要更改的学生信息:')
print('1.学生姓名')
print('2.学生年龄')
print('3.学生班级')
print('4.学生性别')
number = int(input('请输入需要更改的序号:'))
if number == 1:
name1 = input('请输入学生姓名:')
self.students[id_number]['name'] = name1
if number == 2:
age1 = int(input('请输入学生年龄:'))
self.students[id_number]['age'] = age1
if number == 3:
class_number1 = int(input('请输入学生班级:'))
self.students[id_number]['class_number'] = class_number1
if number == 4:
sex1 = input('请输入学生性别(male/famale):')
self.students[id_number]['sex'] = sex1
print('更新后的学生信息如下:')
print(self.students[id_number])
print('==' * 20)
if choose == 5:
frequency = 0
info_list = []
_id_list1 = []
while frequency <= 3:
try:
print('即将进入修改界面~')
print('请更改学生信息:')
student_id = int(input('请输入学号(可多次):'))
_id_list1.append(student_id) # 将需要修改的学生的学号传入列表中,以便更新结束返回信息
ii1 = self.set_info()
_set = {student_id: ii1} # ii == input_info代表输入的信息
info_list.append(_set)
choose_exit = input('是否继续添加?y/n:').lower()
if choose_exit == 'y':
continue
elif choose_exit == 'n':
self.updates(info_list)
print('您已退出~')
print('您修改后的信息如下:')
for i in _id_list1:
print(self.students[i])
print('==' * 20)
break
else:
print('error!!!请输入y/n')
except ValueError:
print(f'请输入正确格式的学号!(输错3次即强制退出,目前{frequency}次)')
frequency += 1
if choose == 6:
id_number = int(input('请输入要删除学生的学号:'))
self.delete(id_number)
print('==' * 20)
if choose == 7:
frequency = 1
_id_list2 = []
while frequency <= 3:
try:
student_id = int(input('请输入学号(可多次)'))
_id_list2.append(student_id)
choose_exit = input('是否继续添加?y/n:').lower()
if choose_exit == 'y':
continue
elif choose_exit == 'n':
print('您已退出~')
print('您删除的学生信息如下:')
for i in _id_list2:
print(self.students[i])
print('==' * 20)
self.deletes(_id_list2)
break
else:
print('error!!!请输入y/n:')
except ValueError:
print(f'请输入正确格式的学号!(输错3次即强制退出,目前{frequency}次)')
frequency += 1
if choose == 8:
print('(下列信息,如某一项不知晓请输入\"0\")')
ii2 = self.set_info()
for d in list(ii2.keys()):
if ii2[d] == 0 or ii2[d] == '0':
ii2[d] = None
print('查找到的学生信息如下:')
for u in self.search(**ii2):
for _id, value in list(u.items()):
print('学号{},姓名{},年龄{},班级{},性别{}'.format(_id, value['name'], value['age'], value['class_number'], value['sex']))
if choose == 9:
frequency = 1
while frequency <= 3:
try:
stu_id = int(input('请输入您所要查找的学生的学号:'))
print(self.get_by_id(stu_id))
break
except ValueError:
print(f'请输入正确格式的学号!(输错3次即强制退出,目前{frequency}次)')
frequency += 1
if choose == 10:
print('您已退出~')
print('==' * 20)
self.__save()
break
except OrderNumberError as e:
print(e)
if __name__ == '__main__':
# 创建Studentinfo类的一个实例, 并把students实际参数传入类中
students_info = StudentsInfo(r'储存学生信息.pickle', '学生系统日志.log')
# 调用类中的server方法
students_info.server()
Python学生信息管理系统-3(完结)
于 2023-06-29 14:32:33 首次发布
这是一个使用Python编写的面向对象的学生信息管理系统,利用pickle模块存储和读取数据,同时集成日志记录功能。系统包括添加、删除、修改和查询学生信息,支持批量操作,并对用户输入和程序异常进行了错误检查和处理。
&spm=1001.2101.3001.5002&articleId=131455826&d=1&t=3&u=e8680445016f4ed2a4f0aeadaa60ca68)
353

被折叠的 条评论
为什么被折叠?



