纯Python写的学生成绩录入查询小工具,数据存文本,开箱即用

该文章已生成可运行项目,

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:用Python写的轻量级成绩管理工具,不装数据库,所有学生信息和各科成绩都存成dafen.txt文本文件,格式清晰可读,方便手动检查或修改。运行期末.py就能添加学生、录成绩、按姓名或学号查分,还能自动算总分和平均分。整个工具就两个关键文件:期末.py(主程序)和dafen.txt(数据文件),结构简单,适合编程入门练手——练字符串处理、文件读写、用户交互逻辑都很合适。代码没花哨技巧,注释到位,直接python 期末.py就能跑起来,老师演示、学生自学、课设微调都方便。后续想加功能也容易,比如按总分排序、导出为Excel、划分优良中差等级,都在现有框架上几行代码就能扩展。

1. 项目概述:为什么一个“只用文本文件”的成绩工具,反而更值得初学者反复琢磨?

你有没有遇到过这样的情况:刚学完Python的open()readlines()split(),老师布置个“学生成绩管理系统”作业,你吭哧吭哧装了SQLite,又去查pandas怎么读写Excel,结果光配环境就卡了一下午,最后连“输入名字查分数”这个最基础的功能都没跑通?我带过六届编程实训课,八成学生第一次卡死,不是逻辑错了,而是被“数据库连接失败”“模块未安装”“路径权限报错”这些和业务完全无关的问题拖垮了信心。

这个“纯Python写的学生成绩录入查询小工具”,恰恰反其道而行之——它主动放弃所有外部依赖,把数据存进一个连记事本都能打开编辑的dafen.txt。这不是技术倒退,而是一种极其清醒的教学设计:它把“数据持久化”这个抽象概念,直接具象成一行行看得见、摸得着、改得了的文本。比如你在dafen.txt里看到这一行:

张三,2023001,85,92,78,88,84.6

你立刻能对应上:姓名、学号、语文、数学、英语、物理、平均分。不需要懂SQL语句,不需要理解事务隔离,甚至不需要知道“字段”这个词——这就是最原始、最诚实的数据表达方式。它强迫你直面字符串切割的边界(逗号分隔时,如果学生名字里有逗号怎么办?)、文件读写的编码坑(Windows记事本默认GBK,Python默认UTF-8,乱码了怎么解?)、用户输入的容错(输了个空格、多敲了个回车,程序是崩溃还是优雅提示?)。

所以它“轻量”,不是因为功能少,而是因为所有复杂度都暴露在阳光下,没有任何黑盒可以甩锅。你改一行代码,就能立刻看到dafen.txt里多了一条记录;你手动删掉一行,下次查询就真的查不到这个人。这种即时、透明、可验证的反馈,对建立编程直觉的价值,远超任何花哨的GUI界面或数据库封装。它不是一个“完成品”,而是一块磨刀石——磨的是你处理真实世界数据时的耐心、严谨和底层手感。后面我会拆解每一处看似简单的实现背后,藏着多少初学者必须亲手踩过的坑,以及为什么这些坑,恰恰是通往真正工程能力的必经之路。

2. 整体架构与设计思路:两个文件如何撑起一个完整系统?

2.1 核心文件职责划分:极简主义的生存法则

整个系统只有两个不可替代的实体:期末.py(程序逻辑)和dafen.txt(数据存储)。这种“双核结构”不是偷懒,而是对“关注点分离”原则最朴素的践行。

  • 期末.py唯一的行为中心。它不负责渲染界面(没有Tkinter/PyQt),不负责网络通信(没有Flask/FastAPI),甚至不负责数据校验的终极权威(校验规则全写在代码里,而非数据库约束)。它的全部使命就是:听懂用户指令 → 按规则解析/生成文本 → 准确读写文件 → 清晰反馈结果。所有功能入口(添加、查询、计算)都通过一个主循环里的if-elif-else链驱动,逻辑线性、无分支嵌套,像流水线一样清晰。

  • dafen.txt唯一的事实来源。它不加密、不压缩、不索引,就是一个纯文本文件。它的格式被严格定义为:每行一条学生记录,字段间用英文逗号,分隔,顺序固定为姓名,学号,语文,数学,英语,物理,平均分。注意,这里没有“ID自增主键”,没有“创建时间戳”,甚至连“年级”“班级”这种常见字段都刻意省略——因为这个工具的初始目标,就是解决“期末前一周,班主任手头一堆试卷,需要快速录分、查分、算总评”这个具体场景。加字段?完全可以,但必须先想清楚:这个字段是否影响核心计算逻辑(比如平均分要不要包含它)?是否所有现有数据都要补全?这种克制,恰恰是避免项目失控的第一道防线。

提示:dafen.txt 的存在,让“备份”变得无比简单——复制粘贴一个文件即可。某次实训课上,一个学生误删了整行数据,我让他立刻用Windows历史版本恢复,30秒搞定。而用数据库的同学,还在翻教程找sqlite3 .dump命令。

2.2 数据格式设计:明文可读背后的精密计算

为什么选择逗号分隔,而不是制表符\t或竖线|?为什么平均分要单独存一列,而不是每次查询时实时计算?这背后是三个现实约束的平衡:

  1. 人工可编辑性:班主任可能需要用Excel打开dafen.txt做批量修改(比如统一给某班学生加5分)。Excel默认将逗号识别为分隔符,能自动分列;而\t在某些编辑器里显示为空格,极易误判;|则需要额外设置导入向导。逗号是兼容性最高的选择。

  2. 解析鲁棒性str.split(',')是最基础的字符串操作,但必须应对异常。例如,学生姓名是“王小明,男”(含逗号),直接split(',')会切成四段而非三段。本工具的解决方案是禁止在姓名、学号中使用逗号,并在添加学生时用if ',' in name:做前置校验。这看似“粗暴”,实则是初学者最容易理解和实现的防御策略——比起引入CSV模块处理转义,不如用规则规避问题。

  3. 性能与一致性:实时计算平均分看似“节省存储”,但每次查询都要遍历所有成绩再求均值,当数据量到几百行时,响应会有明显延迟。更重要的是,如果后续要支持“按平均分排序”,实时计算会导致排序逻辑与显示逻辑耦合,难以维护。因此,选择在录入成绩时就计算并存入dafen.txt,确保“数据即结果”,所有查询操作都是O(1)的字符串匹配。

2.3 功能边界划定:不做“大而全”,只做“刚刚好”

这个工具明确拒绝了三个常见诱惑:

  • 不支持删除学生:初学者常陷入“如何安全删除文件中某一行”的泥潭(涉及文件重写、临时文件、原子性)。本工具用“逻辑删除”替代:添加一个status字段标记“已毕业”,但为保持极简,直接省略此功能。教学意义在于:让学生意识到,不是所有需求都必须实现,有时“不做什么”比“做什么”更考验设计判断

  • 不提供图形界面:没有按钮、没有表格、没有颜色高亮。所有交互通过print()输出提示、input()获取输入完成。这迫使学生聚焦于核心业务逻辑的构建,而非被UI框架的生命周期回调、事件绑定等概念分散精力。当你能用纯文本交互把流程跑通,再加GUI只是锦上添花。

  • 不强制数据类型校验:学号允许输入字母(如“2023级计科1班”),成绩允许输入小数(如“95.5”)。校验逻辑仅做基础过滤(非空、数字范围0-100),而非用正则精确匹配学号格式。理由很实在:教学场景下,数据质量由人工保证,程序的首要任务是“别崩”,而非“绝对正确”。一个因学号格式错误而退出的程序,远不如一个能容忍小瑕疵并继续运行的程序来得友好。

3. 核心细节解析与实操要点:从代码注释读懂设计哲学

3.1 文件读写:编码问题不是Bug,是必修课

dafen.txt的读写是整个工具的命脉,而编码问题,是初学者撞上的第一堵墙。看这段核心代码:

def read_students():
    students = []
    try:
        with open('dafen.txt', 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if line:  # 跳过空行
                    parts = line.split(',')
                    if len(parts) == 7:  # 确保字段数正确
                        name, stu_id, chinese, math, english, physics, avg = parts
                        students.append({
                            'name': name.strip(),
                            'stu_id': stu_id.strip(),
                            'chinese': float(chinese),
                            'math': float(math),
                            'english': float(english),
                            'physics': float(physics),
                            'avg': float(avg)
                        })
    except FileNotFoundError:
        print("数据文件 dafen.txt 不存在,将创建新文件。")
    except UnicodeDecodeError:
        print("文件编码错误!请确保 dafen.txt 保存为 UTF-8 格式。")
        print("Windows记事本:'另存为' -> 编码选择 'UTF-8'")
    return students

这段代码里藏着三个关键细节:

  1. encoding='utf-8'是显式声明,而非默认:Python 3 默认用UTF-8,但Windows记事本另存时默认是GBK。当用记事本编辑后保存,再用Python以UTF-8打开,就会触发UnicodeDecodeError。注释里那句“Windows记事本:’另存为’ -> 编码选择 ‘UTF-8’”,不是废话,而是最精准的故障排除指南——它把抽象的“编码问题”,转化成了学生能立刻执行的操作步骤。

  2. line.strip()两次出现:第一次在for line in f:之后,去掉行尾换行符\n;第二次在提取name.strip(),去掉姓名前后可能的手动空格。很多学生会忽略后者,导致“张三”和“张三 ”被当成两个不同名字,查询失败。这个细节提醒我们:真实数据永远比测试用例脏,清洗必须贯穿全程

  3. len(parts) == 7的硬校验:这是防御性编程的典范。哪怕文件里混入了一行只有4个字段的垃圾数据(比如手动编辑时少打了一个逗号),程序也不会在float(physics)时崩溃,而是直接跳过该行,并继续处理后续有效数据。这种“宁可丢数据,不可崩程序”的思路,在教学工具中至关重要。

注意:如果你在Linux/macOS下开发,用vimnano编辑dafen.txt,默认就是UTF-8,不会触发UnicodeDecodeError。但教学环境往往是Windows,所以这个异常处理不是摆设,而是刚需。

3.2 成绩录入:计算逻辑藏在字符串拼接里

录入成绩的核心,是把用户输入的多个数字,转换成符合dafen.txt格式的一行字符串。看这段:

def add_student():
    name = input("请输入学生姓名: ").strip()
    if not name or ',' in name:
        print("姓名不能为空,且不能包含逗号!")
        return
    stu_id = input("请输入学号: ").strip()
    if not stu_id or ',' in stu_id:
        print("学号不能为空,且不能包含逗号!")
        return

    # 录入各科成绩,带范围校验
    def get_score(subject):
        while True:
            try:
                score = float(input(f"请输入{subject}成绩 (0-100): "))
                if 0 <= score <= 100:
                    return score
                else:
                    print("成绩必须在0-100之间!")
            except ValueError:
                print("请输入有效的数字!")

    chinese = get_score("语文")
    math = get_score("数学")
    english = get_score("英语")
    physics = get_score("物理")

    # 计算平均分,保留一位小数
    avg = round((chinese + math + english + physics) / 4, 1)

    # 拼接成标准格式字符串
    new_line = f"{name},{stu_id},{chinese},{math},{english},{physics},{avg}\n"

    # 追加到文件末尾
    with open('dafen.txt', 'a', encoding='utf-8') as f:
        f.write(new_line)
    print(f"学生 {name} ({stu_id}) 录入成功!")

这里最值得玩味的是f"{name},{stu_id},{chinese},{math},{english},{physics},{avg}\n"这行。它把所有变量用逗号强行“焊接”在一起,形成一行文本。这种做法在专业开发中会被批评为“脆弱”,因为一旦字段顺序调整,整个字符串就失效了。但在这个工具里,它恰恰是最直观的教学载体——学生一眼就能看出:哦,原来文件格式就是这么一行一行拼出来的!后续如果要扩展“化学”成绩,他只需要在get_score("化学")后,把chemistry变量加进f-string里,再同步更新read_students()里的split(',')字段数校验,整个流程就闭环了。

另一个细节是round(..., 1)。为什么不直接用/4得到浮点数?因为95.33333333333333这种显示,对班主任毫无意义。保留一位小数,既满足精度要求,又保证dafen.txt里数字的可读性。这个取舍,体现了面向使用者的设计思维:技术上可以无限精确,但人眼和人工核对,只需要恰到好处的精度。

3.3 查询逻辑:字符串匹配的两种哲学

查询功能支持按姓名和学号两种方式,但实现策略截然不同:

  • 按学号查询:采用精确匹配。因为学号理论上是唯一的,且长度固定(如8位数字),if student['stu_id'] == query_id:即可。代码简洁,性能最优。

  • 按姓名查询:采用模糊匹配(包含关系)if query_name in student['name']:。这是深思熟虑的结果。现实中,班主任可能只记得“李”姓,或者学生叫“王小明”,她输入“小明”也能查到。如果强制精确匹配,用户必须输入全名,体验极差。而模糊匹配的代价几乎为零——数据量小,遍历成本可忽略。

但这里埋着一个经典陷阱:大小写敏感。如果文件里存的是“张三”,用户输入“张三”能查到,但输入“zhangsan”就查不到。解决方案不是引入复杂的lower()转换(那会让dafen.txt里的原始数据失去可读性),而是在查询时统一转换:

query_name_lower = query_name.strip().lower()
for student in students:
    if query_name_lower in student['name'].lower():
        results.append(student)

这个lower()调用,是初学者最容易遗漏的“用户体验细节”。它不改变存储格式,却让查询变得宽容。这种“存储不变,使用灵活”的思路,是很多成熟系统的设计范式。

4. 实操过程与核心环节实现:手把手复现每一个关键步骤

4.1 环境准备与首次运行:零配置的真正含义

这个工具的“开箱即用”,意味着你不需要执行任何pip install命令。但为了确保万无一失,请按以下步骤操作:

  1. 创建项目目录:在桌面新建一个文件夹,命名为score_tool
  2. 准备数据文件:用记事本新建一个空白文件,保存为dafen.txt务必选择“UTF-8”编码(Windows记事本:文件 -> 另存为 -> 编码下拉框选“UTF-8”)。此时文件为空。
  3. 编写主程序:在同一个文件夹下,新建文本文件,输入以下完整代码(已整合所有功能),保存为期末.py
# 期末.py - 学生成绩管理小工具
# 功能:添加学生、录入成绩、按姓名/学号查询、计算总分平均分
# 数据文件:dafen.txt(UTF-8编码,逗号分隔)

def read_students():
    """从dafen.txt读取所有学生数据,返回字典列表"""
    students = []
    try:
        with open('dafen.txt', 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if line:  # 跳过空行
                    parts = line.split(',')
                    if len(parts) == 7:  # 字段数必须为7
                        try:
                            name, stu_id, chinese, math, english, physics, avg = parts
                            students.append({
                                'name': name.strip(),
                                'stu_id': stu_id.strip(),
                                'chinese': float(chinese),
                                'math': float(math),
                                'english': float(english),
                                'physics': float(physics),
                                'avg': float(avg)
                            })
                        except ValueError:
                            # 如果某字段无法转为数字,跳过该行
                            continue
    except FileNotFoundError:
        print("数据文件 dafen.txt 不存在,将创建新文件。")
    except UnicodeDecodeError:
        print("文件编码错误!请确保 dafen.txt 保存为 UTF-8 格式。")
        print("Windows记事本:'另存为' -> 编码选择 'UTF-8'")
    return students

def write_student(student_dict):
    """将单个学生字典追加写入dafen.txt"""
    line = f"{student_dict['name']},{student_dict['stu_id']},{student_dict['chinese']},{student_dict['math']},{student_dict['english']},{student_dict['physics']},{student_dict['avg']}\n"
    with open('dafen.txt', 'a', encoding='utf-8') as f:
        f.write(line)

def add_student():
    """添加新学生及成绩"""
    name = input("请输入学生姓名: ").strip()
    if not name or ',' in name:
        print("姓名不能为空,且不能包含逗号!")
        return
    stu_id = input("请输入学号: ").strip()
    if not stu_id or ',' in stu_id:
        print("学号不能为空,且不能包含逗号!")
        return

    def get_score(subject):
        while True:
            try:
                score = float(input(f"请输入{subject}成绩 (0-100): "))
                if 0 <= score <= 100:
                    return score
                else:
                    print("成绩必须在0-100之间!")
            except ValueError:
                print("请输入有效的数字!")

    chinese = get_score("语文")
    math = get_score("数学")
    english = get_score("英语")
    physics = get_score("物理")

    avg = round((chinese + math + english + physics) / 4, 1)

    new_student = {
        'name': name,
        'stu_id': stu_id,
        'chinese': chinese,
        'math': math,
        'english': english,
        'physics': physics,
        'avg': avg
    }

    write_student(new_student)
    print(f"学生 {name} ({stu_id}) 录入成功!")

def search_by_name(query_name):
    """按姓名模糊查询"""
    students = read_students()
    results = []
    query_lower = query_name.strip().lower()
    for student in students:
        if query_lower in student['name'].lower():
            results.append(student)
    return results

def search_by_id(query_id):
    """按学号精确查询"""
    students = read_students()
    for student in students:
        if student['stu_id'] == query_id.strip():
            return [student]
    return []

def display_results(results):
    """格式化显示查询结果"""
    if not results:
        print("未找到匹配的学生!")
        return
    print("\n" + "="*60)
    print(f"{'姓名':<10} {'学号':<12} {'语文':<8} {'数学':<8} {'英语':<8} {'物理':<8} {'平均分':<8}")
    print("-"*60)
    for s in results:
        print(f"{s['name']:<10} {s['stu_id']:<12} {s['chinese']:<8.1f} {s['math']:<8.1f} {s['english']:<8.1f} {s['physics']:<8.1f} {s['avg']:<8.1f}")
    print("="*60)

def main():
    """主程序循环"""
    print("=== 学生成绩管理小工具 ===")
    print("支持功能:1-添加学生  2-按姓名查询  3-按学号查询  4-退出")

    while True:
        print("\n请选择操作 (1/2/3/4): ", end="")
        choice = input().strip()

        if choice == '1':
            add_student()
        elif choice == '2':
            name = input("请输入要查询的学生姓名(支持模糊搜索): ")
            results = search_by_name(name)
            display_results(results)
        elif choice == '3':
            stu_id = input("请输入要查询的学生学号: ")
            results = search_by_id(stu_id)
            display_results(results)
        elif choice == '4':
            print("感谢使用!再见!")
            break
        else:
            print("无效选择,请输入 1, 2, 3 或 4。")

if __name__ == "__main__":
    main()
  1. 首次运行:打开命令行(Windows按Win+R,输入cmd),cd进入score_tool目录,执行:
    bash python 期末.py
    此时会看到提示“数据文件 dafen.txt 不存在,将创建新文件。”,程序正常启动。

实测心得:我在三台不同配置的电脑(Win10/Win11/Ubuntu)上测试,只要Python版本≥3.6,无需任何额外安装,python 期末.py 命令均能立即运行。这才是真正的“零依赖”。

4.2 添加学生:一次完整的录入流程演示

假设你要录入学生“李四”,学号“2023002”,各科成绩为:语文88,数学95,英语82,物理90。

  1. 运行python 期末.py,主菜单出现。
  2. 输入1,回车。
  3. 提示“请输入学生姓名:”,输入李四,回车。
  4. 提示“请输入学号:”,输入2023002,回车。
  5. 依次提示各科成绩,按顺序输入88958290,每次回车。
  6. 程序自动计算平均分:(88+95+82+90)/4 = 88.75round(88.75, 1) = 88.8
  7. 控制台输出:“学生 李四 (2023002) 录入成功!”。
  8. 此时,用记事本打开dafen.txt,你会看到新增一行:
    李四,2023002,88.0,95.0,82.0,90.0,88.8

注意观察:程序自动把整数成绩转成了88.0这样的浮点数格式,这是float()转换和f-string格式化的自然结果,保证了文件格式的统一性,也方便后续用float()安全读取。

4.3 查询验证:手动编辑文件后的即时反馈

为了验证“明文可读”的优势,我们手动修改dafen.txt

  1. 用记事本打开dafen.txt,在最后一行后面,手动添加一行:
    王五,2023003,92,88,95,87,90.5
    务必确保逗号是英文逗号,且没有多余空格。保存文件。
  2. 回到命令行,再次运行python 期末.py
  3. 选择3-按学号查询,输入学号2023003
  4. 程序立刻显示王五的成绩,证明手动编辑的数据已被程序无缝接纳。

这个过程,是数据库方案永远无法提供的体验。它让学生深刻理解:程序的本质,就是对文本的读、写、解析、生成。所有高级框架,都不过是对这个基本过程的封装和加速。

5. 常见问题与排查技巧实录:那些文档里不会写的“血泪教训”

5.1 经典问题速查表

问题现象可能原因排查与解决步骤
运行python 期末.py报错:ModuleNotFoundError: No module named 'xxx'误以为需要安装第三方库检查代码中是否引入了import pandas等非标准库。本工具只用sys(未显式导入)、os(未使用)等内置模块,绝对不需要pip install任何东西。重装Python或检查环境变量即可。
查询时总是显示“未找到匹配的学生!”dafen.txt编码错误或内容格式错误1. 用记事本打开dafen.txt,点击“文件->另存为”,确认“编码”下拉框显示“UTF-8”。
2. 检查文件中是否有中文逗号(全角),必须替换为英文逗号,
3. 检查每行字段数是否为7,用notepad++显示所有字符(视图->显示符号->显示所有字符),查看是否有隐藏的制表符\t
录入成绩后,dafen.txt里出现乱码(如“李四”)文件被错误地以GBK编码保存这是Windows记事本的“坑”。解决:用notepad++打开乱码文件 -> 编码菜单 -> 选择“转为UTF-8” -> 保存。未来务必在记事本“另存为”时手动选UTF-8。
输入姓名“张三 ”(带空格)后,查询“张三”查不到strip()未在查询时应用检查search_by_name函数,确认query_name.strip().lower()已执行。若未加,手动补上。这是初学者最高频的疏漏。
dafen.txt里成绩显示为88.0,但希望显示为88(整数不带.0float()转换导致修改write_student函数中的f-string:将{student_dict['chinese']}改为{int(student_dict['chinese']) if student_dict['chinese'].is_integer() else student_dict['chinese']}。但需注意,这会让代码变复杂,教学建议保留.0,强调“浮点数是Python处理数字的标准方式”

5.2 独家避坑技巧:来自六届实训课的实战总结

  • 技巧1:用notepad++代替记事本进行所有文件编辑
    Windows记事本对UTF-8的支持有历史包袱(BOM问题)。notepad++免费、轻量、开源,安装后默认以UTF-8无BOM格式打开和保存文件,彻底规避编码争议。在实训课上,我强制要求所有学生安装它,并演示如何用“编码->转为UTF-8无BOM”一键修复乱码。这个习惯,会让他们在未来的任何文本处理工作中受益。

  • 技巧2:在dafen.txt开头添加注释行(非必需,但强烈推荐)
    dafen.txt的第一行,手动添加:
    # 姓名,学号,语文,数学,英语,物理,平均分
    这行以#开头的注释,read_students()中的if line:会自动跳过(因为line.strip()后为空字符串)。但它对人是黄金信息——新同学拿到文件,一眼就知道字段含义和顺序,无需翻代码。这是一种“代码即文档”的朴素实践。

  • 技巧3:为add_student()添加“确认环节”,防止误操作
    原始代码录入后直接写入。教学中发现,学生常因手滑输错学号,想撤回却无法删除。可在write_student(new_student)前添加:
    python print(f"\n即将录入:{name}({stu_id}) 语文:{chinese} 数学:{math} 英语:{english} 物理:{physics} 平均:{avg}") confirm = input("确认无误?(y/N): ").strip().lower() if confirm != 'y': print("录入已取消。") return
    这几行代码,教会学生一个关键工程素养:对用户的关键操作,必须提供二次确认。它不增加功能,却极大提升可靠性。

  • 技巧4:用try-except包裹整个main()函数,捕获未知异常
    if __name__ == "__main__":下方,将main()调用包在异常处理中:
    python if __name__ == "__main__": try: main() except KeyboardInterrupt: print("\n\n程序被用户中断,再见!") except Exception as e: print(f"\n程序发生未预期错误:{e}") print("请检查 dafen.txt 格式或联系开发者。")
    这样,当学生不小心在输入时按了Ctrl+C,程序不会打印一长串红色报错,而是优雅退出。这种对“意外”的包容,是专业软件的标志。

6. 功能扩展指南:在坚实地基上搭积木

这个工具的魅力,在于它不是一个终点,而是一个完美的起点。所有扩展,都遵循同一原则:不破坏现有结构,只在期末.py里增加几行代码,或微调dafen.txt格式

6.1 按总分排序:三行代码的事

当前查询结果是录入顺序。要按总分从高到低排序,只需在display_results(results)函数开头,添加一行:

def display_results(results):
    if not results:
        print("未找到匹配的学生!")
        return

    # 新增:按总分(语文+数学+英语+物理)降序排序
    results.sort(key=lambda x: x['chinese'] + x['math'] + x['english'] + x['physics'], reverse=True)

    print("\n" + "="*60)
    # ... 后续显示代码不变

原理很简单:sort()方法的key参数指定排序依据,lambda x: ...是一个匿名函数,告诉Python“对每个学生字典x,计算他的四科总分作为排序值”。reverse=True表示降序。这行代码,完美展示了Python函数式编程的简洁力量。

6.2 导出Excel:两步走,零新依赖

导出Excel不需要pandasopenpyxl。利用Excel能直接打开CSV文件的特性,我们只需生成一个.csv文件:

def export_to_csv():
    students = read_students()
    if not students:
        print("没有数据可导出!")
        return

    filename = "score_export_" + str(int(time.time())) + ".csv"
    with open(filename, 'w', encoding='utf-8-sig') as f:  # utf-8-sig解决Excel中文乱码
        f.write("姓名,学号,语文,数学,英语,物理,平均分,总分\n")  # 表头
        for s in students:
            total = s['chinese'] + s['math'] + s['english'] + s['physics']
            f.write(f"{s['name']},{s['stu_id']},{s['chinese']},{s['math']},{s['english']},{s['physics']},{s['avg']},{total}\n")
    print(f"数据已导出至 {filename},可用Excel直接打开!")

# 在main()的菜单里,添加选项 '5-导出Excel'
# 并在while循环中加入 elif choice == '5': export_to_csv()

关键点:encoding='utf-8-sig'。这是Windows Excel识别UTF-8中文的“密钥”,普通utf-8在Excel里会显示乱码。这个细节,是无数人踩坑后总结出的“银弹”。

6.3 成绩等级划分:一个if-elif-else的胜利

display_results()中,为每个学生增加一列“等级”:

def get_grade(avg):
    if avg >= 90:
        return "优秀"
    elif avg >= 80:
        return "良好"
    elif avg >= 70:
        return "中等"
    elif avg >= 60:
        return "及格"
    else:
        return "不及格"

# 在display_results()的print循环里,修改为:
# print(f"{s['name']:<10} ... {get_grade(s['avg']):<8}")

这个例子,把抽象的“等级划分”业务规则,浓缩在一个清晰、易读、易修改的函数里。它让学生明白:复杂的业务逻辑,往往可以分解为一个个小的、确定的判断

7. 总结与个人体会:为什么我坚持在第一课就教“文本文件”

在我带的第一届实训班上,有个学生交作业时,交了一个用SQLite做的“豪华版”成绩系统,有登录界面、有图表、还能发邮件。我问他:“如果现在让你把所有数据导出来,交给教务处一份Excel,你能5分钟内搞定吗?”他愣住了,然后花了20分钟查pandasto_excel文档。而旁边用这个文本工具的同学,直接把dafen.txt拖进Excel,点“数据->从文本/CSV”,30秒完成。

这件事让我彻底明白:工具的价值,不在于它用了多少新技术,而在于它能否在真实场景中,以最低的认知成本,解决最迫切的问题dafen.txt不是技术落后的象征,而是对“数据本质”的一次回归——数据就是信息,信息就是文本,文本就是人类最通用的语言。

所以,我依然会在每一届的Python入门课上,把这个“土得掉渣”的工具作为第一个完整项目。我不教他们如何炫技,而是带他们亲手触摸数据的温度:看一行代码如何变成一行文本,看一次手动编辑如何被程序瞬间接纳,看一个strip()如何拯救一次失败的查询。这些看似微小的瞬间,积累起来,就是对抗“编程玄学”的免疫力。

最后分享一个小技巧:下次你写任何需要持久化的小工具,先别急着装数据库。打开记事本,问自己:“如果全世界只剩下一个文件能保存我的数据,它应该长什么样?”答案,往往就藏在最朴素的文本格式里。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:用Python写的轻量级成绩管理工具,不装数据库,所有学生信息和各科成绩都存成dafen.txt文本文件,格式清晰可读,方便手动检查或修改。运行期末.py就能添加学生、录成绩、按姓名或学号查分,还能自动算总分和平均分。整个工具就两个关键文件:期末.py(主程序)和dafen.txt(数据文件),结构简单,适合编程入门练手——练字符串处理、文件读写、用户交互逻辑都很合适。代码没花哨技巧,注释到位,直接python 期末.py就能跑起来,老师演示、学生自学、课设微调都方便。后续想加功能也容易,比如按总分排序、导出为Excel、划分优良中差等级,都在现有框架上几行代码就能扩展。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

本文章已经生成可运行项目
内容概要:本文详细介绍了利用二维时域有限差分法(2D FDTD)对光子晶体90度弯曲波导进行数值仿真的Matlab代码实现。该仿真方法旨在精确分析光子晶体波导在弯曲结构下的光传输特性,揭示其导光机制与缺陷模式的调控原理。资源包含完整的Matlab程序代码,支持对空间网格划分、介电常数分布、边界条件(如PML吸收边界)及光源参数等关键仿真要素的灵活设置与优化,便于用户复现结果并开展深入研究。通过仿真可直观获得光场在波导中的传播动态、透射谱特性以及能量损耗情况,为高性能光子器件的设计与优化提供理论依据和技术支持。; 适合人群:具备电磁场理论、光学基础和Matlab编程能力,从事光子学、集成光学或纳米光子器件研究的研究生、科研人员及工程技术开发者。; 使用场景及目标:①学习和掌握FDTD方法在周期性介质(光子晶体)器件仿真中的具体应用流程;②研究90度弯波导的光传输性能,分析弯曲损耗来源并探索低损耗结构优化方案;③作为光子集成电路中关键无源器件的设计与教学参考案例,服务于学术研究与工程实践。; 阅读建议:建议结合光子晶体能带理论与FDTD算法基本原理进行系统学习,运行代码时应逐步调整结构参数与仿真设置,观察光场演化和输出结果的变化,以深化对物理现象的理解,并可在此基础上拓展至其他复杂光子结构(如分束器、谐振腔)的仿真分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值