用python写学生信息管理系统v1.3(持续更新中)

学生信息管理系统v1.3 - - python

- 内容

  • 对上节实现的学生信息管理系统进行重构,要求实现日志功能和异常处理功能。

  • 使用系统自带库 logging 和 shelve,不引入第三方库

  • 导入 sys 包,使用 sys.exit( ) 可退出程序。

  • 数据要求的改变:学生的身高和体重使用数字类型存储。

  • 学生信息管理系统v1.0

  • 学生信息管理系统v1.1

  • 学生信息管理系统v1.2

本次升级所用到的python知识

- 错误和异常

  • 语法错误

Python 的语法错误或称为解析错误,经常被初学者所碰到

count = 0

while (count < 10)
    print('本次的count是: ',count)
    count += 1

print('count输出结束。')

运行后会出现如下错误,是因为 while 后缺少冒号(:)
用python写学生信息管理系统v1.3(持续更新中)_第1张图片

  • 异常

即便 Python 程序语法是正确的,在运行时也有可能出现错误,在运行时检测到的错误称为异常

print(10*(1/0))

运行时会产生如下异常,因为 0 不能作为除数
在这里插入图片描述
因为在程序中难免会碰到此类问题,所以在程序中必须对可能发生的错误进行处理,否则程序会因为各种问题终止并退出。

而 Python 内置了一套异常处理,来帮助我们进行错误的处理。

- 异常处理

  • try…except 语句

当我们认为某些代码可能会出错时,就可以用 try 来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即 except 语句块。

以下为拦截 0 作为除数发生的异常:

try:
    print('try...')
    r = 10 / 0
    print('result:', r)
except ZeroDivisionError as e:
    print('except:', e)
finally:
    print('finally...')
print('END')

运行后结果如下:
用python写学生信息管理系统v1.3(持续更新中)_第2张图片从输出结果可见,当错误发生后,后续语句 print(‘result:’, r) 不会被执行,expect 由于捕获到 ZeroDivisionError,因此被执行,然后程序继续走,执行 finally。

  • Python 定义的主要异常
- BaseException                     # 所有异常的父类
    - SystemExit                     # 由sys.exit()抛出的异常
    - KeyboardInterrupt              # 通常由ctrl+c或者Delete抛出的异常
    - GeneratorExit                  # 当生成器被关闭时抛出的异常
    - Exception                      # 
        - StopIteration              # 迭代结束异常
        - StopAsyncIteration         # 由异步迭代的`__anext__()`抛出的异常
        - ArithmeticError            # 各种算数错误引起的异常
            - FloatingPointError     # 浮点数操作错误
            - OverflowError          # 结果超出范围
            - ZeroDivisionError      # 0为除数异常
    - AssertionError                 # assert错误异常
    - AttributeError                 # 属性引用异常
    - BufferError                    # 缓存错误
    - EOFError                       # 读不到数据
    - ImportError                    # import错误
        - ModuleNotFoundError        # 找不多模块
    - LookupError                    # 由索引和key值引起的异常
        - IndexError                 # 索引错误
        - KeyError                   # 字典key值错误
    - MemoryError                    # 内存溢出异常
    - NameError                      # 本地和全局找不到变量名
        - UnboundLocalError          # 局部变量没有赋值
    - OSError                        # system错误
        - BlockingIOError            # 调用阻塞异常错误
        - ChildProcessError          # 子进程
        - ConnectionError            # 连接
            - BrokenPipeError        # 管道读写异常
            - ConnectionAbortedError # 连接失败
            - ConnectionRefusedError # 连接拒绝
            - ConnectionResetError   # 连接重置
        - FileExistsError            # 创建文件和文件夹错误
        - FileNotFoundError          # 文件未找到
        - InterruptedError           # 中断错误
        - IsADirectoryError          # 文件操作用在文件夹上
        - NotADirectoryError         # 不是文件夹
        - PermissionError            # 权限
        - ProcessLookupError         # 进程不存在
        - TimeoutError               # 超时
    - ReferenceError                 # 引用异常
    - RuntimeError                   # 
        - NotImplementedError        # 运行抽象方法
        - RecursionError             # 超出最大递归深度
    - SyntaxError                    # 语法错误
        - IndentationError           # 缩进错误
            - TabError               # tab错误
    - SystemError                    # 解释器中断
    - TypeError                      # 类型错误
    - ValueError                     # 赋值错误
        - UnicodeError               # 
            - UnicodeEncodeError     # unicode编码错误
            - UnicodeDecodeError     # unicode解码错误
            - UnicodeTranslateError  # unicode转换错误
    - Warning                        # 
        - DeprecationWarning         # 操作不赞成警告
        - PendingDeprecationWarning  # 表明此操作将来会被弃用
        - UserWarning                # 用于用户生成警告
        - SyntaxWarning              # 语法可疑警告
        - RuntimeWarning             # 运行警告
        - FutureWarning              # 将会改变警告
        - ImportWarning              # 导入警告
        - UnicodeWarning             # unicode相关警告
        - BytesWarning               # 字节相关警告
        - ResourceWarning            # 资源使用情况警告
  • try 如何工作

1)首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)。
2)如果没有异常发生,忽略 except 子句,try 子句执行后结束。
3)如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。最后执行 try 语句之后的代码。
4)如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。

  • 多种异常

如果发生了不同类型的错误,应该由不同的 except 语句块处理(类似于多重 if)。

try:
    r = 10 / int(input('请输入: '))
except ValueError as e:
    print('ValueError:', e )
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
finally:
    pass
print('END')

输入 a 运行:
用python写学生信息管理系统v1.3(持续更新中)_第3张图片输入0运行:
用python写学生信息管理系统v1.3(持续更新中)_第4张图片
如果没有错误发生,可以在 except 语句块后加一个 else,当没有错误发生时会自动执行 else 语句。

try:
    r = 10 / int(input('请输入: '))
except ValueError as e:
    print('ValueError:', e )
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('r =', r)
finally:
    pass
print('END')

输入 2 运行:
用python写学生信息管理系统v1.3(持续更新中)_第5张图片

  • 跨层调用

使用 try…except 捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数 main( ) 调用 foo( ),foo( ) 调用 bar( ),结果 bar( ) 出错了,这时,只要 main( ) 捕获到就可以处理。

在异常处理机制中,Python 实现的跨层调用相对于C++、Java比较方便。

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        print('Error:', e)
    finally:
        print('finally...')

if __name__ == '__main__':
    main()

也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写 try…except…finally 的麻烦。

  • 记录错误

如果不捕获错误,自然可以让 Python 解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。

Python 内置的 logging 模块可以非常容易地记录错误信息:

import logging

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

try:
    bar('0')
except Exception as e:
    logging.exception(e)

print('END')
  • 调试与日志

程序能一次写完并正常运行的概率很小,当遇到复杂 bug 时,我们需要一套调试程序的手段来修复。

logging 日志就是一种很好的处理,logging 不会抛出错误,而且可以输出到文件:

import logging

logging.basicConfig(level = logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n )
print(10 / n)

这就是 logging 的好处,它允许你指定记录信息的级别,有 debug,info,warning,error 等几个级别,当我们指定 level= INFO 时,logging.debug 就不起作用了,其余同理。这样就可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。

  • 日志书写格式
import logging

logging.basicConfig(
    level=logging.INFO,  #定义输出到文件的log级别
    format='%(asctime)s %(filename)s %(levelname)s %(message)s',  #日志格式
    datefmt='%Y-%m-%d %A %H:%M:%S',  #日期格式 年(大写) 月 日 星期 时 分 秒
    filemode='a',  #不能用W,被覆盖后查看不到之前录入信息
    filename='zuoye8-1.log'  #文件名
)  # 设定日志

- 学生信息管理系统v1.3

代码如下:

  • shelve库
# coding: utf-8
# Time: 2021/9/15 15:37
# Author: pinkward
# Software: PyCharm

# 此代码仅在系统第一次运行前执行,做数据文件的初始化

import shelve # 导入模块

studic = {
     
'x':{
     'name':'pinkward','height(cm)':'180','weight(kg)':'65','class':'x1','tel':'11111111111'}
}  # 初始存储数据 子字典形式储存
f = shelve.open('stu')  # stu文件
f['studic'] = studic  # 存入studic字典
f['gly'] = {
     'admin': '123456'}  # 存入gly字典
f.close()
# coding: utf-8
# Time: 2021/9/20 14:37
# Author: pinkward
# Software: PyCharm

# 学生信息管理系统v1.3

import shelve
import logging
import sys # python自己的描述环境

logging.basicConfig(
    level=logging.INFO,  #定义输出到文件的log级别
    format='%(asctime)s %(filename)s %(levelname)s %(message)s',  #日志格式
    datefmt='%Y-%m-%d %A %H:%M:%S',  #日期格式 年(大写) 月 日 星期 时 分 秒
    filemode='a',  #不能用W,被覆盖后查看不到之前录入信息
    filename='zuoye8-1.log'  #文件名
)  # 设定日志

f = shelve.open('stu') # 从文件中读入数据
try:
    studic = f['studic']
    gly = f['gly'] # 读入数据 如果为空拦截报错
except KeyError as e:
    print('数据文件损坏,无法使用')
    logging.error('数据文件损坏,无法使用')
    f.close()
    sys.exit()
finally:
    f.close()

def query(): # 查询函数
    if len(studic):
        for x in studic: # 用for循环访问studic字典
            stu = studic[x] # 依据学号 将子字典赋给stu
            print('--学号:', x) # 输出键
            print('\t姓名:    ', stu['name'])
            print('\t身高(cm):', stu['height(cm)'])
            print('\t体重(kg):', stu['weight(kg)'])
            print('\t班级:    ', stu['class'])
            print('\t电话:    ', stu['tel']) # 拿出子字典中的值
    else:
        print('---当前无学生信息!---')

def insert(): # 添加函数
    xh = input('请输入学生学号: ')
    if not xh or xh in studic: # 判断系统内是否有该学号
        print('---此学号已存在!请重新输入:---')
    else: # 学生的各项信息均为必填项
        while 1:
            name = input('请输入姓名: ')
            if name:
                break
        while 1:
            try:
                height = int(input('请输入身高: '))
                if height and (height > 50 and height < 230):
                    break
                else:
                    print('身高必须在50~230之间!')
            except ValueError as e:
                print('身高必须是数字!')
                logging.error('身高必须是数字!')
        while 1:
            try:
                weight = int(input('请输入体重: '))
                if weight and (weight > 40 and weight < 200):
                    break
                else:
                    print('体重必须在40~200之间!')
            except ValueError as e:
                print('体重必须是数字!')
                logging.error('体重必须是数字!')
        while 1:
            bj = input('请输入班级: ')
            if bj:
                break
        while 1:
            tel = input('请输入电话: ')
            if tel:
                break
        studic[xh] = {
     'name': name, 'height(cm)': height, 'weight(kg)': weight, 'class': bj, 'tel': tel} # 存入字典
        print('---已成功录入学生信息!---')

def update(): # 修改函数
    xh = input('请输入学生学号: ')
    if xh and xh not in studic: # 判断系统内是否有该学号
        print('---此学号不存在!请重新输入:---')
    else:
        while 1:
            name = input('请输入姓名: ')
            if name:
                break
        while 1:
            try:
                height = int(input('请输入身高: '))
                if height and (height > 50 and height < 230):
                    break
                else:
                    print('身高必须在50~230之间!')
            except ValueError as e:
                print('身高必须是数字!')
                logging.error('身高必须是数字!')
        while 1:
            try:
                weight = int(input('请输入体重: '))
                if weight and (weight > 40 and weight < 200):
                    break
                else:
                    print('体重必须在40~200之间!')
            except ValueError as e:
                print('体重必须是数字!')
                logging.error('体重必须是数字!')
        while 1:
            bj = input('请输入班级: ')
            if bj:
                break
        while 1:
            tel = input('请输入电话: ')
            if tel:
                break
        studic[xh] = {
     'name': name, 'height(cm)': height, 'weight(kg)': weight, 'class': bj, 'tel': tel} # 存入字典
        print('---已成功修改学生信息!---')

def delete(): # 删除函数
    xh = input('请输入学生学号: ')
    if xh not in studic: # 判断系统是否有该学号
        print('---此学号不存在!请重新输入:---')
    else:
        del studic[xh] # 删除键即删除值 实现删除信息功能
        print('---成功删除该学号学生信息!---')

def editmanager(): # 维护函数
    while 1:
        mname = input('请输入管理员用户名:')
        if mname:
            break
    while 1:
        mpwd1 = input('请输入管理员密码: ')
        if mpwd1:
            break
    while 1:
        mpwd2 = input('请再次输入管理员密码: ')
        if mpwd2:
            break
    if mname and mpwd2 == mpwd1:
        gly.clear()
        gly[mname] = mpwd2
        print('---维护管理员信息成功!---')
    else:
        print('---用户名或密码错误!---')

def main(): # main函数
    print()
    print('欢迎使用学生信息管理系统v1.3!'.center(50))
    username = input('请输入用户名: ')
    password = input('请输入密码: ')
    if username in gly and password == gly[username]:
        while 1:
            while 1:
                print()
                print('学生信息管理系统v1.3'.center(50))
                print('系统菜单'.center(52))
                print('1.添加学生信息'.center(50))
                print('2.删除学生信息'.center(50))
                print('3.修改学生信息'.center(50))
                print('4.查看学生信息'.center(50))
                print('5.维护管理员信息'.center(52))
                print('6.退出管理系统'.center(50))
                opt = input('请选择功能: ')
                if not opt or opt not in '123456' or len(opt) > 1:
                    print('---无效选项!请重新选择:---')
                    continue
                else:
                    break # 确保正确输入进入功能选项
            if opt in '1':
                insert() # 调用添加函数
            elif opt in '2':
                delete() # 调用删除函数
            elif opt in '3':
                update() # 调用修改函数
            elif opt in '4':
                query() # 调用查询函数
            elif opt in '5':
                editmanager() # 调用维护函数
            else:
                f = shelve.open('stu') # 将现有信息写入文件
                f['studic'] = studic
                f['gly'] = gly  # 存入当前信息
                f.close()
                break # 退出管理系统
        print('---已成功退出!---')
        print('感谢使用学生信息管理系统v1.3!'.center(50))
    else:
        print('---普通用户登录成功!---') # 普通用户页面
        while 1:
            while 1:
                print()
                print('欢迎使用学生信息管理系统v1.3!'.center(50))
                print('系统菜单'.center(52))
                print('4.查看学生信息'.center(50))
                print('5.退出管理系统'.center(50))
                opt = input('请选择功能: ')
                if not opt or opt not in '45' or len(opt) > 1:
                    print('---无效选项!请重新选择:---')
                    continue
                else:
                    break # 确保正确输入进入功能选项
            if opt in '4':
                query() # 调用查询函数
            else:
                break # 退出管理系统
        print('---已成功退出!---')
        print('感谢使用学生信息管理系统v1.3!'.center(50))

if __name__ == '__main__': # 判断是否为自主运行
    main() # 调用main函数


你可能感兴趣的:(学生信息管理系统v.py,python,pycharm)