Python新手进阶必练:3个综合练习题带你从会语法到做项目
发布时间:2026/10/2 15:00:46来源:尧图网络
我接触过很多刚学完Python基础的人大家面临的最普遍困境不是“不会写语法”而是“不知道学了之后能做什么”。列表、字典、循环、函数单独拿出来都能说得头头是道但一遇到一个稍微完整一点的需求立马卡壳先干什么、后干什么、拆成几个函数、出错怎么办完全没概念。这种时候给自己安排3个综合练习题目比盲刷一百道填空题有用得多。这篇文章里的3个综合练习题目不是从题库里随便摘的零碎作业而是按“从会语法到会做完整小工具”的进阶路径拆出来的训练方案。每道题都刻意把好几个知识点串在一起文件操作、数据结构、异常处理、第三方库、面向对象、数据库、单元测试。做完这三道题你会对整个“从需求到代码”的流程有实实在在的体感。说明一下我的原意标题虽然是“3个综合练习题目”但综合题的价值从来不在于“题目数量”而在于每道题覆盖的知识面有多宽、做题时能得到什么反馈。我会把三道题的设计意图、实现思路、参考代码、常见坑点全部拆开讲你能直接照着练也可以把这套思路拿去做培训带教。下面进入正题。1. 综合练习题目为什么是新手阶段的必需品先说一个我在带人过程中反复看到的规律只练语法题的人进步速度普遍慢练完整小项目的人哪怕代码写得不太好三个月后的水平也会明显高一截。原因不复杂——语法题考查的是“你会不会用这个语法”综合题考查的是“你能不能把一个模糊的想法变成一个能跑的程序”这是两种完全不同的能力。只写语法题容易让人产生一种“我都学会了”的错觉。比如你熟练掌握了正则表达式能写出匹配邮箱的正则但当你面对一个真实的日志文件需要从十几万行文本里提取所有IP地址并按次数排序时你会发现单纯的语法知识根本不够用。你要处理文件编码问题要考虑性能要去重要排序要输出格式化结果——每一个环节都是一个小坑。综合练习题目存在的意义就是把这一连串小坑提前让你踩一遍。另外一个很多人忽略的点综合题能帮你建立“模块化思维”。一道合格的综合练习题天然要求你把功能拆分成若干个责任清晰的函数或类。你不可能把整个需求写成一个几百行的while循环那样调试起来会怀疑人生。你被迫去思考“这个功能应该由谁负责”“哪些代码应该复用”“参数应该怎么传”这就是工程思维的萌芽。我还想强调一个最简单的原因成就感。语法题的成就感很短暂程序运行的瞬间就是它价值的上限。但一个综合练习题做出来之后你可以真实地拿给朋友看可以持续使用可以迭代改进甚至能作为求职时的项目作品。这种正向反馈对坚持学习这件事来说太重要了。所以想突破“只能跟题走、不能自己写程序”这个瓶颈最好的办法就是直接上手做综合练习题目。下面这套“3个综合练习题目”就是我从这个角度设计出来的。2. 三道练习题的设计思路从语法串联到项目实战这三道题从易到难恰好对应三个训练阶段第一阶段训练基础语法串联能力第二阶段训练真实数据处理能力第三阶段训练代码组织与持久化能力。每一道题的侧重点都不一样但它们又有明显的递进关系避免你一直停留在同一水平线上重复。2.1 第1题学生成绩管理系统——串联基础语法这道题看起来简单但它其实覆盖了Python入门阶段最重要的几个点列表与字典的组合使用、函数拆分、文件读写、排序、异常处理。学生成绩管理是典型的CRUD练习需求也很直白能从CSV文件里读取学生成绩能按平均分排名能按课程筛选能统计全班及格率最后把排名结果写回一个新文件。你可能觉得“这不就是读文件然后算平均数吗”但真正动手后你会发现光是决定用什么数据结构来存每位学生的多科成绩就有不少讲究。存成列表套字典还是列表套列表要不要用dataclass每门课的分数怎么高效取值这些看似细枝末节的选择恰恰决定了后面所有计算的代码复杂度。我特意把这道题放在第一个是因为它不需要第三方库只用Python内置模块就能完成非常适合已经不满足于语法题、但还没接触过项目化开发的人。做这道题时你不应该把目光只放在“结果对不对”上更应该留意自己的代码组织方式有没有写出一个几百行的主函数有没有复制粘贴重复代码这些坏习惯会在后面两道题里加倍惩罚你。2.2 第2题电商销售数据分析与可视化——打通数据处理链路第二道题开始进入真实世界的场景给你一份几万行的电商订单CSV文件里面有订单号、日期、客户ID、商品名、品类、单价、数量。题目要求做数据清洗、计算总销售额和月度趋势、统计各品类销售占比、找到销量Top 10商品最后生成一份图文报告。这道题的核心不是“算出来”而是“面对脏数据怎么办”。真实的数据文件里一定有空值、重复行、格式不统一的日期、变成文本的数字。如果你用纯内置库去处理光是清洗就得写上百行所以我建议直接用pandas和matplotlib。这也是大多数人进入数据分析领域前会遭遇的第一次“真实工程训练”先用df.info()和df.head()建立对数据的感知再决定清洗策略。这道题的价值在于打通整条链路读取——清洗——处理——聚合——可视化——输出报告。每一个环节都有独立的坑把它们串起来后你就拥有了一个可以迁移到任何表格类任务的通用框架。之后不管面对的是销售数据、用户数据还是项目数据做事的思路都是一样的。2.3 第3题个人记账本工具——综合面向对象与持久化设计第三道题在难度上明显跳了一档。我要求实现一个命令行个人记账本支持收入和支出的增删改查按分类管理数据持久化到SQLite数据库提供月度收支统计并且模拟预算超支提醒。做这道题时你要是还像第一题那样把所有代码堆在一个文件里那代码会很痛苦。这道题刻意安排了三个新挑战面向对象设计、数据库持久化、单元测试。你必须把“账单记录”抽象成类把“对账单的操作”和“数据存储”分离还要用装饰器或上下文管理器来处理日志记录。在动手之前应该先画出这个“系统”由哪几个类组成每个类有哪些方法和属性类之间怎么协作。这个过程听起来像设计文档实际上是最值得花时间的部分比直接写代码重要得多。做完这道题你已经不是“会写Python程序”的状态而是“会做一个可持续使用的工具”的状态。有了这三题做底子再去接触Web开发、爬虫、自动化测试等方向都会轻松很多。3. 在动手之前先建立自检清单很多人在做综合练习题的时候心态就是“赶紧写赶紧跑通跑通就算完”。这个思路很可惜。综合练习题目真正值钱的地方在于锻炼你“评估自己代码”的能力。所以我建议你在动手前先把自检清单立起来每做完一题逐条对照检查。3.1 功能完整度怎么检查功能完整性最容易检查但也最容易丢分。做法很简单把题目里的每一条需求抄成清单然后一条一条打勾。学生成绩系统的需求就不自觉间要求你掌握5个知识点——这些必须项一一核对。很多同学不是功能写不对其实是“漏了”某个分支建议重点确认新增数据后是否真的写回文件、空文件是否有逻辑处理等。功能完整不等于“主流程跑通就行”。你要问自己用户输入非法数据时程序会崩溃还是给出提示第二次运行程序时上一次的数据还在不在如果文件不存在程序是报一长串堆栈错误还是提示清晰的中文说明这些问题直接决定你的程序是“只能在题目环境下运行”还是“任何场景下都站得住”。后者才是综合练习题的真实目标。3.2 代码质量怎么评估代码质量可以从几个角度快速自评变量命名是什么水平函数是否只做一件事有没有大段重复代码主流程是否被拆得足够短。我给你一个非常实用的判断方法把整个程序里最长的那个函数拿出来如果它的行数超过50行大概率是职责过多。不要急着说“我这个函数就是干完所有活”然后继续堆代码。正确做法是觉得“想给这段代码起个名字了”就把它拆出去。第一题里排名计算、文件保存、控制台输出这三件事绝对不应该写在同一个函数里。函数是最终客观判断问题的。另一个值得关注的指标是“改动成本”如果产品经理突然说把按平均分排名改成按总成绩排名你要改几行代码如果你的答案是“改好几个地方并且还要担心漏改”说明你的代码耦合度过高。好的结构是改一个函数的输入或内部实现其他模块完全不受影响。3.3 边界处理和异常输入最容易被扣分这是初学者最容易忽略、也是最容易拉开差距的部分。三个综合练习题目里我设置了很多针对边界的陷阱也是平时上课重点讲解的难点第一题成绩文件里有一门课分数缺失第二题订单里出现重复订单号第三题用户输入了一个负数金额。你会怎么处理正确的做事方式是在写代码之前先问自己这个程序到底会接收到什么输入然后决定哪些输入是合法的、哪些是不合法的并把非法输入的兜底逻辑写进去。pandas处理日期时也这样遇到无效值不要直接让整个程序崩溃而是用errorscoerce把无效值变成NaT再集中处理。内存和资源也要考虑第二题几万行数据如果全塞进列表没问题但如果百万行呢你也估计不了陌生人的机器环境别总假设自己看到的路径在别人机器上也能用。开源库的核心就解决的是“生产环境综合问题”分析业务场景一道一道逐步清理这才是专业选手和业余选手的分水岭。我按不同的层次整理了一个自评表你可以直接作为参考检查维度具体检查点建议权重功能完整性题目所有需求覆盖菜单/入口可达数据能持久化40%健壮性非法输入不崩溃缺文件可提示空数据可处理20%代码结构函数按职责拆分命名清晰无明显重复代码20%工程细节路径相对化编码明确主入口清晰有测试意识20%这组权重是我个人常用的评估习惯你未必照搬但至少要在动手前先明白“什么算做好”。有了这把尺子才能避免陷入“程序能跑就万事大吉”的误区。4. 三题核心实现路线与关键代码解析章节到这我把三道题具体的实现路线和代码骨架写出来。需要考虑的是代码是可以参考的但我不建议直接照抄尤其是第三题。综合练习题的目的在于让你走一遍从思考到落地的完整过程直接复制代码等于只看答案不做题效果会大打折扣。4.1 第1题实现路线数据结构先行异常兜底第一题拿到手后先别马上写读取文件的代码。第一步想清楚一个问题每个学生用什么样的数据结构表示最推荐的做法是“列表套字典”或使用dataclass。每一位学生是一个对象对象内部再存一份课程到分数的映射。比如from dataclasses import dataclass dataclass class Student: name: str scores: dict # 示例{语文: 88, 数学: 92, 英语: 85} def average(self): return sum(self.scores.values()) / len(self.scores)把成绩和平均分方法放在一起是“数据行为”的面向对象雏形。虽然第一题不强制用面向对象但用这个模式会明显减少后续排序、统计时的混乱。接着把文件读取和排名保存分别拆成两个函数。import csv def load_students(csv_path): students [] try: with open(csv_path, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: name row[姓名] scores {k: float(v) for k, v in row.items() if k ! 姓名} students.append(Student(namename, scoresscores)) except FileNotFoundError: raise FileNotFoundError(f找不到成绩文件{csv_path}) return students def save_rank_file(csv_path, students): with open(csv_path, w, encodingutf-8, newline) as f: writer csv.DictWriter(f, fieldnames[姓名, 平均分]) writer.writeheader() for s in sorted(students, keylambda x: x.average(), reverseTrue): writer.writerow({姓名: s.name, 平均分: round(s.average(), 2)})注意csv.DictReader默认会把每一行包装成字典表头作为键这是初学者最容易忽略的地方。排序时sorted的reverseTrue参数也不能漏漏掉后默认升序排名规则就反了。异常处理我建议至少覆盖文件不存在、某门课分数是空值、数字无法转成float。这几种情况如果不处理数据文件稍微有一点点脏整个程序就会崩。关于汉字编码文件读写一定要统一推荐读取和写入都显式声明encodingutf-8。用Windows的同学如果控制台或文件打开后出现乱码极大概率就是编码问题。这个坑在Python文件处理中非常高频提早修炼对后面所有题都有好处。4.2 第2题实现路线清洗比分析更花时间进入第二题我会直接快进到大数据处理流程。拿到订单CSV第一步一定是数据预览这句话我恨不得用黑体加粗加大。很多人在read_csv之后就开始算销售额完全不了解数据长什么样最后得出各种奇奇怪怪的数字还以为是程序写错了。正确的起手式是import pandas as pd df pd.read_csv(orders.csv) print(df.info()) print(df.head()) print(df.isna().sum()) print(df.duplicated().sum())这一长串探路做完你对数据的基本情况就有了数。然后按顺序处理删除重复行、把日期列转成datetime类型、计算销售额列、处理缺失值。df df.drop_duplicates() df[日期] pd.to_datetime(df[日期], errorscoerce) df[销售额] pd.to_numeric(df[单价], errorscoerce) * pd.to_numeric(df[数量], errorscoerce) df df.dropna(subset[日期, 销售额])这里有两个易错点。第一pd.to_datetime遇到无法解析的日期时会把整列传染成object类型必须加errorscoerce把非法日期转成NaT再用dropna统一剔除。第二单价和数量在原始文件里很可能是字符串尤其单价带着“¥”符号或空格的时候直接相乘会报错或得出NaN。所以要先转为数值errorscoerce继续兜底。聚合维度也需要提前想清楚。月度销售额、品类销售额、商品Top10对应的分别是时间维度的聚合、分类字段的聚合、具体商品的聚合。我用一段代码把三种聚合写全monthly_sales df.resample(ME, on日期)[销售额].sum() category_sales df.groupby(品类)[销售额].sum().sort_values(ascendingFalse) top10_products df.groupby(商品名)[销售额].sum().nlargest(10) import matplotlib.pyplot as plt monthly_sales.plot(kindline, title月度销售额趋势) plt.show() category_sales.head(10).plot(kindbar, title品类销售额 Top 10) plt.show()这里的“ME”是pandas近期版本的月度聚合结尾字符串老版本可能接受“M”。如果你在自己环境遇到提示就去查一下当前版本的resample用法这对灵活查阅文档能力也是一次练习。画完图以后把结果整理成一份Markdown报告会是个灵魂升华。我不建议用一堆print输出更好的做法是把分析结论写进一个report.md文件让别人打开这个文件就能看懂全部分析结论。这一步看似不起眼但它逼你组织语言、沉淀结论真实工作里也是常态化操作。数据清洗在整个数据分析项目里通常占掉60%以上的时间你做完这道题以后会有刻骨铭心的体会。4.3 第3题实现路线先画类图再写数据库最后写业务第三个练习如果不动脑直接开写很快就会把自己卡死。我个人建议的前置工作是先在纸上列出来这个系统包括哪几个关键类Record单条账单数据包含类型收入/支出、金额、分类、备注、发生时间Budget预算配置保存到独立的数据库表AccountService业务操作入口负责增删改查和统计ReportGenerator生成月度统计和报表文本根据这个划分核心的数据库表结构可以这样建CREATE TABLE IF NOT EXISTS records ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL CHECK(type IN (income, expense)), amount REAL NOT NULL CHECK(amount 0), category TEXT NOT NULL, remark TEXT DEFAULT , created_at TEXT NOT NULL );注意几个细节金额用REAL类型但业务层必须约束它为正数type字段加CHECK约束防止脏数据写入created_at我建议直接存ISO格式的字符串例如2026-02-14 10:30:00在SQLite里比较和按月分组都很方便。接下来是业务逻辑层这是很多初学者最陌生的部分。关键词是“参数绑定不能拼接SQL”。课程里我会把一条SQL执行时的风险用意外事件类比提醒你如果你把用户输入直接拼到SQL字符串里等于让自己程序里凭空出现一扇任意输入都能通往数据库的暗门这是绝对不可接受的。正确做法是import sqlite3 from datetime import datetime class AccountService: def __init__(self, db_pathaccount.db): self.conn sqlite3.connect(db_path) # 注意数据库连接按需创建不能全局共享到多线程 def add_record(self, type_, amount, category, remark): if amount 0: raise ValueError(金额必须大于0) if type_ not in (income, expense): raise ValueError(类型必须是income或expense) cur self.conn.execute( INSERT INTO records (type, amount, category, remark, created_at) VALUES (?, ?, ?, ?, ?) , (type_, amount, category, remark, datetime.now().isoformat(timespecseconds)), ) self.conn.commit() return cur.lastrowid这里我特意演示了两层防御入参校验在业务层做一次数据库约束在SQL层再做一次。这种做法虽然“重复”但对真实项目来说却是标准的纵深防御。面向对象设计里我还希望看到“装饰器”和“上下文管理器”的影踪。一种常见做法是写一个log_call装饰器自动打印每次操作的方法名和耗时模拟线上系统的审计日志。如果你之前没写过装饰器这题恰好给了你一个刚需的应用场景比单纯背语法定义深刻得多。单元测试是第三题隐藏的加分项。SQLite天然支持:memory:可以生成销毁的临时库。单元测试里创建一个内存数据库测试再正常不过把测试用例和真实文件彻底隔离速度也飞快。下面是一小段示范import unittest from account_service import AccountService class TestAccountService(unittest.TestCase): def setUp(self): self.service AccountService(:memory:) def test_add_record_balance_validation(self): with self.assertRaises(ValueError): self.service.add_record(expense, -5, 餐饮) def test_month_stats(self): self.service.add_record(income, 10000, 工资) self.service.add_record(expense, 2500, 房租) stats self.service.stats_by_month(datetime.now().strftime(%Y-%m)) self.assertEqual(len(stats), 2)如果你做到这一步说明你已经开始把“写代码”和“验证代码”两类行为分开来看了这个认知对后面进入任何团队写作都极其宝贵。5. 做题过程中的高频坑点与排查心得这三道题我从不同批次的练习者手里观察到的报错以及自己反复踩过的坑汇总成了一张速查表。遇到报错时先对照这张表可以大幅缩短排查时间。5.1 高频报错速查表现象可能原因处理方法UnicodeEncodeErrorWindows控制台默认编码不是UTF-8在入口处配置sys.stdout.reconfigure(encodingutf-8)文件读写统一指定编码文件明明存在但报FileNotFoundError路径里反斜杠被当成转义符用相对路径并把路径写作data/grades.csv或使用原始字符串rdata\grades.csvpandas列名有空格或隐藏字符表头混入不可见字符用df.columns.str.strip()清洗列名日期列显示为object日期格式混杂pd.to_datetime(df[日期], errorscoerce)后再dropna排序后数据看起来没有变化忘掉reverseTrue或未重新赋值在项目里约定好平均分排名几乎都是降序改完数据重新运行却恢复原状只是内存里改了没写入文件每个增删改函数调用后立即执行文件/数据库写入并commitsqlite3.OperationalError: table records already exists重复执行创建表语句建表统一使用CREATE TABLE IF NOT EXISTSmatplotlib画图后没有任何窗口弹出没有调用plt.show()检查是否有plt.show()Jupyter里还需%matplotlib inline这张表不是让你背下来的而是希望你形成一种习惯遇到报错先读最后一行看的是异常类型而不是那些刺眼的traceback堆栈把前因后果写下来再对比这种模式是否在以前的题里出现过。这类“元认知”能力往往是拉开差距的关键。5.2 从“能出结果”到“能给别人用”的升级经验三道题做完大多数人停留在“能跑”阶段。我的建议是拿出半天时间给其中一道题做一次“交付级”升级让它从能跑变成能给别人用。首推修改第二题。把它包装成一个命令行工具接受输入的CSV路径自动输出一个带图表和报告的结果文件夹。这样别人只需要一条命令就能完成整个分析流程。你需要用到argparse或者简单的input参数读取把CSV路径、输出目录从写死的代码里提出来。然后是输出形式的端正。不要用print输出一堆散落的数字把分析结果整理成一个可读的Markdown或Excel文件。再想清晰“重点结论放在前面”总销售额、同比环比、Top品类、异常日期。这样一看就是一个可以提交给业务方的东西。这种升级训练是让综合练习题从“练习题”变成“作品”的最后一步。也是很多人在简历里能写上“独立完成xxx工具开发”的真实底气。5.3 三题结束后如何继续往下走做完这三题之后下一步怎么选取决于你想进哪个方向。想做Web开发可以先拿其中的记账本做改造加上Flask或FastAPI提供HTTP接口再写一个简单的登录页面。想做数据方向可以把第二题的几万行订单数据换得更脏一些比如混入多地区多币种重写一遍清洗流程。想做自动化测试可以围绕第三题系统补一套更全面的pytest测试覆盖每一个方法的分支。最后再分享一个我实际带人的习惯做完一道综合练习题后回头看一眼自己最早写的版本。不用修改就纯看。绝大多数人会发现一周前的自己写的代码为什么那么绕现在一眼就能看出哪里能简化、哪里会崩溃、哪里命名有问题。这个对比过程带来的满足感和修正力比做任何新题都强烈。它说明你真正在成长而这正是综合练习题目存在的意义——你不需要第一次就写对但你需要知道下一次还能怎么写更好。
网站建设高端定制企业官网