ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python上机练习第七天:数据处理综合训练,文件读取与字典统计

Python上机练习第七天:数据处理综合训练,文件读取与字典统计 这篇文章记录的是“上机练习第七天”的全过程。带过新人的讲师都知道前六天学完 Python 基础语法学员的状态基本都是“每个知识点都见过合在一起就卡壳”。所以我的第七天上机从来不排新课专门用来做第一次综合练习——拿一个真实的小需求让学员把文件读取、数据清洗、循环统计、排序输出完整走一遍。这个设计对自学入门、刚入职实习、以及在带新人的讲师都有参考价值你可以把它当成一份练习资料也可以照这个流程复刻一节实训课。第七天是一个很有意思的时间节点。前六天学了变量、分支、循环、列表、字典、函数看起来什么都碰过了但一旦面对一个完整需求很多人连第一步“从哪儿开始”都不知道。上机练习的价值恰恰在这里它不是再考一个语法点而是逼着你在没有提示的情况下自己把学过的零件组装成一台能转的机器。这篇记录会把第七天的任务设计、代码实现、遇到的问题和排查过程全部拆开讲哪怕你完全没带过班只是自己在学编程也可以照着练一遍。1. 第七天上机练习的定位从“会语法”到“能干活”1.1 前六天积累的知识点第七天要怎么用很多培训课程喜欢天天塞新知识但我自己的经验是第六天结束以后必须停下来做一次综合串联否则后面的函数进阶、异常捕获、模块化全部是空中楼阁。第七天要达成的目标很简单把所有基础语法在同一个真实场景里跑通。为了说明这一天的设计逻辑我一般会把前六天的内容列成一张对照表让学员自己看清楚这节课到底在复习什么前六天学到的能力第七天对应练习的具体用法变量与数据类型用字符串存每行数据用浮点数保存金额条件判断判断空行、判断解析失败的坏数据循环用 for 循环逐行读取文件列表与元组用列表保存所有订单用元组保存单条订单信息字典用字典做区域销售额汇总、订单状态计数函数基础把主逻辑包在 main() 函数里养成结构化习惯字符串与文件读写split 拆列、strip 去空格、open 读写文件这张表我自己每次都会发给学员。它的作用不是背知识点而是让学员看到“第七天没有新内容只是换了一种考法”。很多学员做完以后会跟我说原来觉得字典没什么用现在才知道字典做统计有多顺手。这就是上机练习的意义——语法只有在问题里被用过一次才真正长在身上。1.2 为什么第一个综合项目选“数据处理”而不是“小游戏”第七天选什么题目我纠结过很久。最常见的选择是写一个猜数字游戏或者贪吃蛇因为学员会觉得有趣课堂气氛也热闹。但如果你真在教学一线待过会发现一个尴尬的事实小游戏项目在“逻辑嵌套”上很容易走火入魔——一个 while 循环套 if 判断再套另一个 while学员一旦绕进去整节课就变成了调试循环反而没有机会练习文件读写和数据整理能力。我更推荐用“数据处理小报表”作为第一个完整项目原因是它的工程链路非常清晰读文件、清洗数据、统计数据、排序结果、写出报告。每一步都独立每一步都可以用肉眼检查对不对而且这个方向最接近真实工作——运营给你一份表让你算个汇总这是很多职场新人的第一课。打个比方前六天好比练习切菜、热锅、调汁看着都会了但第七天是第一次完整做一道菜。题目不能太难刀工、火候、调味都要覆盖到。数据处理刚好满足它不像“开发一个网站”那样需要太多前置知识又能把基础语法串成完整闭环。第七天的上机节奏我一般这样控制前 60 分钟让学员独立完成主流程不允许相互讨论代码可以看笔记但不能看现成答案中间 30 分钟允许互相帮助最后 20 分钟集中复盘常见错误。整体难度控制在“有一点挑战但跳一跳够得着”的程度。2. 任务书设计销售明细汇总2.1 任务书与预期输出第七天的题目我长期使用一份固定的任务书细节会微调但框架不变。这里直接把它写出来如果你要自己练可以照着复制一份。任务背景运营部门发来一份销售明细文件sales_data.csv里面包含订单日期、区域、品类、销售额和订单状态。现在需要用 Python 写一个程序完成以下统计统计每个区域的销售总额统计每个订单状态的数量找出销售金额最高的 5 条订单把计算结果输出到summary_report.txt。为了让练习可控要求暂时不使用 csv 模块和第三方库只用基础的文件读写和字符串操作。这个限制在第七天非常关键因为 csv 模块会帮我们自动处理引号和分隔符但也会掩盖“split 之后列数对不上”这类经典问题。先让学员用最原始的方式处理数据后面再学工具才知道工具在解决什么问题。数据文件的内容大致长这样日期,区域,品类,销售额,订单状态 2025-03-01,华东,数码,1299.00,已完成 2025-03-01,华南,服饰,399.00,已完成 2025-03-02,华北,食品,86.50,已完成 2025-03-02,华东,书籍,59.90,退款 2025-03-03,华南,数码,2199.00,待发货当然我会故意在文件里混入一些脏数据比如空行、金额带上了符号、或者某一行少了一列。这些“坑”是上机练习的核心价值比顺顺利利跑完更能锻炼排查能力。预期输出文件summary_report.txt的格式大概是各区域销售总额 华东: 3523.45 华南: 2898.50 华北: 1356.00 各订单状态数量 已完成: 5 待发货: 2 退款: 1 销售金额最高的5条订单 2025-03-05 华南 数码 3899.00 待发货 ...2.2 动手之前用伪代码把链路画出来第七天我最强调的一件事就是“拿到需求不要急着敲键盘”。很多新手打开编辑器以后的第一反应是凭感觉写两行然后越写越乱。正确做法是先用伪代码把完整的处理流程写出来哪怕只是简单几行也能帮你把输入、处理、输出三件事分清楚。我给的参考伪代码是这样的1. 打开文件并读取所有行 2. 跳过表头 3. 遍历每一行 3.1 去掉首尾空白 3.2 跳过空行 3.3 按逗号拆分成多列 3.4 如果列数不是5列跳过并打印警告 3.5 把销售额转成浮点数失败则跳过 3.6 用清洗后的数据更新三个容器订单列表、区域汇总字典、状态统计字典 4. 对订单列表按销售额排序取前5名 5. 打开输出文件写入三部分结果不要小看这个步骤。第七天上机最容易卡住的地方往往不在某个语法而是“我不知道自己现在写到哪一步了”。伪代码就是给程序画路标每一段都有明确出口写代码时心里有数调试时也容易定位。同时我会让学员在动笔前先回答一个问题“如果我是人手里拿着一张纸我会怎么统计这些数据”几乎所有学员都能回答一行行看看到华东就把金额加到一个总数里看到“已完成”就画一个正字。伪代码其实就是把这种人类思维翻译成计算机步骤。你能说出来怎么算就能写出来代码怎么跑。3. 核心代码实现逐段拆解第七天上机题3.1 读取文件with open 是把安全锁很多第一次接触文件操作的人习惯用open()然后忘记close()。在第七天我会直接要求统一使用with open的写法with open(sales_data.csv, r, encodingutf-8) as f: lines f.readlines()这里with的作用是自动管理资源代码块执行完文件自动关闭不会出现句柄泄漏的问题。encodingutf-8是另一个细节Windows 下默认编码经常是 gbk如果不显式指定读带中文的 CSV 很容易直接报UnicodeDecodeError。我会让学员故意先不写这个参数亲眼看到报错再让他们改成utf-8这样印象会非常深。读取以后我要求学员做的第一件事不是处理而是打印前 3 行看看print(lines[:3])这一步看似多余实际上价值巨大。它确认了三件事文件路径找对了、编码读对了、表头长什么样清楚了。很多学员文件打不开问题往往出在“程序在 A 目录运行文件放在 B 目录”路径都没对上后面全是白费。先打印前几行至少把“读文件”这一步先钉死。3.2 清洗数据不要让一行脏数据毁掉整个统计CSV 看起来简单但脏数据比你想象的更常见。第七天我会故意给数据文件里塞几个坑有一行是空行有一行金额写成了1,299有一行只有 4 列。如果不对这些情况做防护程序跑着跑着要么崩溃要么统计结果莫名其妙少了一大块。核心清洗代码我这样写for line in lines[1:]: line line.strip() if not line: continue parts line.split(,) if len(parts) ! 5: print(f跳过异常行: {line}) continue date, region, category, amount_str, status [p.strip() for p in parts] try: amount float(amount_str) except ValueError: print(f金额无法解析: {amount_str}) continue这里有几个关键点要讲透。line.strip()是去掉首尾的空白字符包括换行符否则最后一行经常带着\n容易让解析出错。if not line判断空行处理完以后如果这行是空的直接跳过。parts line.split(,)是按逗号拆成列表这里最容易踩的坑是如果金额是1,299那么split之后这一行会变成 6 列和预期不符。所以我要求先检查长度不对就跳过而不是让它悄悄污染后面的数据。[p.strip() for p in parts]是一个列表推导式把每一列的前后空格都去掉。“已完成”和“已完成 ”看似差不多但在字典统计里是两个不同的键这种隐蔽问题很难查。列表推导式在第七天属于“学有余力”的内容但用过一次以后学员基本都会爱上这种写法。金额转换用float(amount_str)包在try里是第七天的一个核心知识点。正常的数据直接转换就行但如果遇到1,299这种格式float()会直接抛出ValueError。用try/except不是为了让程序假装没事而是把这种脏数据挡在统计之外并打印一行提示让操作者知道到底丢弃了哪些数据。3.3 统计与排序字典和 sorted 的组合拳清洗完的数据要放进三个容器里。第一个是所有订单的原始信息后面排 Top 5 要用第二个是“区域 - 销售总额”的映射第三个是“订单状态 - 数量”的映射。orders.append((amount, date, region, category, status)) region_total[region] region_total.get(region, 0) amount status_count[status] status_count.get(status, 0) 1orders是一个列表里面存的是元组。元组的顺序我在代码里定为(amount, date, region, category, status)为什么把金额放第一位因为后面排序的时候我们按照元组的第一个元素来排金额在前面代码会更简洁。region_total.get(region, 0)是第七天最容易忽略但最实用的一个写法。字典的get方法会在键不存在时返回默认值这里默认值是 0。没有学过这个写法的人通常要写一个if region in region_total的判断代码瞬间多出三行。get解决的痛点就是“取不到就补一个默认值再参与计算”理解了这个逻辑后面学defaultdict也会顺畅很多。统计完成以后要做排序。先给基础版用普通函数当排序依据def get_amount(item): return item[0] top5 sorted(orders, keyget_amount, reverseTrue)[:5]sorted的key参数指定“按照什么来排序”这里item[0]就是之前放在元组第一位的金额。reverseTrue表示降序取前 5 名用列表切片[:5]。这个思路还可以直接用匿名函数写成一行但我会建议基础薄弱的学员先老老实实用普通函数因为可读性更好。这里有一个经典大坑如果拿原始字符串amount_str去排序结果大概率是错的。比如字符串比较时9.5会比10.2大因为比较是从第一个字符开始逐个比 ASCII 值。这就是必须在清洗阶段就把金额转换成float的根本原因。我会让学员故意跑一次错误版本看一眼前 5 名里出现了几百块的订单然后再改成浮点数版本对比这个坑踩一次就会记一辈子。3.4 输出报告 完整参考代码最后一步是把统计结果写到文件里。输出要和控制台显示分开因为结果文件是要交付的不能只靠人眼盯着屏幕。with open(summary_report.txt, w, encodingutf-8-sig) as f: f.write(各区域销售总额\n) for region, total in region_total.items(): f.write(f{region}: {total:.2f}\n) f.write(\n各订单状态数量\n) for status, cnt in status_count.items(): f.write(f{status}: {cnt}\n) f.write(\n销售金额最高的5条订单\n) for amount, date, region, category, status in top5: f.write(f{date} {region} {category} {amount:.2f} {status}\n)这里我特别强调encodingutf-8-sig。很多学员用utf-8写文件结果用 Excel 打开时中文乱码发现原因是 Excel 需要读到 UTF-8 的 BOM 头。utf-8-sig会在文件开头写入一个不可见的标识Excel 就能正确识别编码。这个细节不做一次真的记不住我在第七天会让所有学员统一用utf-8-sig写文本文件。下面的完整参考代码可以直接跑通方便读者对照练习。我用一份内置样例数据来说明整体结构def main(): orders [] region_total {} status_count {} with open(sales_data.csv, r, encodingutf-8) as f: lines f.readlines() for line in lines[1:]: line line.strip() if not line: continue parts line.split(,) if len(parts) ! 5: print(f跳过异常行: {line}) continue date, region, category, amount_str, status [p.strip() for p in parts] try: amount float(amount_str) except ValueError: print(f金额无法解析: {amount_str}) continue orders.append((amount, date, region, category, status)) region_total[region] region_total.get(region, 0) amount status_count[status] status_count.get(status, 0) 1 def get_amount(item): return item[0] top5 sorted(orders, keyget_amount, reverseTrue)[:5] with open(summary_report.txt, w, encodingutf-8-sig) as f: f.write(各区域销售总额\n) for region, total in region_total.items(): f.write(f{region}: {total:.2f}\n) f.write(\n各订单状态数量\n) for status, cnt in status_count.items(): f.write(f{status}: {cnt}\n) f.write(\n销售金额最高的5条订单\n) for amount, date, region, category, status in top5: f.write(f{date} {region} {category} {amount:.2f} {status}\n) if __name__ __main__: main()完整跑完以后学员需要自己打开summary_report.txt检查数字是否符合预期。我会给一个简单的验证方法手动拉一个区域筛选比如数一数华东有多少行把金额加起来然后和程序输出比对。这一步不能省因为只有对比过人工结果和程序结果才算真正验证了逻辑而不是仅仅“没报错”。4. 第七天上机常见问题与排查技巧4.1 六类高频报错与排查表第七天上机期间学员遇到的问题来来去去就是那几个。我每期都会在教室白板上更新“报错墙”把高频问题直接挂出来学员看到别人也踩同样的坑心态会稳很多。下面这六类问题几乎覆盖了百分之八十的情况表格可以直接收藏错误现象可能原因排查建议UnicodeDecodeError: gbk codec cant decode文件是 UTF-8 编码但 open 没指定编码在open()中加上encodingutf-8ValueError: could not convert string to float金额列里有、逗号或多余空格先打印这一行用replace()去掉符号再转换拆分后列数不对或统计结果缺失行里有中文逗号或数据本身包含逗号打印parts看实际内容检查原始文件Top 5 排序结果明显不对金额还是字符串按字符排序了确认在统计前已经float(amount_str)输出的 txt 中文打开乱码写入时用了utf-8Excel 不识别写入文件时改成encodingutf-8-sig提示找不到文件FileNotFoundError程序和 CSV 不在同一个目录用os.getcwd()打印当前目录改用绝对路径这几个问题里排序那个最隐蔽。第七天学员往往会想我明明是按“销售额”排的序为什么几万块的订单排到了后面原因就是数据在 CSV 里是字符串看起来是数字但sorted不会帮你自动做类型转换。检验方法很简单打印每一条订单的金额类型print(type(amount))一看是str就知道问题在哪。4.2 排查习惯先打印再思考上机练习最有价值的部分不是一次写对而是学会在写错以后怎么找到问题。第七天我会反复强调一件事如果程序没有跑出预期结果第一件事不是改代码而是加打印。比如区域汇总不对就先在循环里加一行print(region, amount)跑一遍看打印出来的数据是不是和文件里一样。数据进了循环却没有进统计说明if条件或者字典更新那行有问题数据压根没进循环说明前面的空行判断或者split长度判断把它拦掉了。用打印把程序“透明化”一行行看比坐在那里猜要高效得多。我还让学员养成“分阶段验证”的习惯。读文件后打印前 3 行清洗后打印一行处理结果统计完打印字典内容排序完打印前 1 条。每一步都验证一次就不会出现最后写报告时才发现前面全错了的崩溃局面。4.3 卡住之后怎么办30 分钟法则第七天最怕的就是学员一个人死磕到底。我的经验是一个新手上机遇到问题如果自己尝试 30 分钟还没有任何进展继续耗下去边际效益会越来越低。这不是鼓励大家不思考而是让你学会筛选有些问题是知识盲区想也想不出来有些问题是手误静下来看一遍就能发现。所以我定了一个“30 分钟法则”先自己对照伪代码排查用打印法缩小范围20 分钟还没有头绪就允许看五分钟笔记还不行的用一句话把问题描述出来找旁边的人或老师求助。描述问题时必须说清楚三件事我期望的结果是什么实际得到的结果是什么我打印了哪一行数据发现异常。能把这个描述清楚求助效率会高很多。这里也顺便回答一个被问过很多次的问题上机练习允许看笔记吗我的答案是允许但有一个前提——看笔记不是为了找现成代码而是为了查某一个函数名怎么拼。第七天的目标是把思路转成代码不是背 API所以语法忘了可以翻思路卡住了绝对不能直接抄别人的成品。5. 第七天之后怎么把这次练习真正吃透5.1 第一轮升级把主流程封装成函数第七天上机完成以后我通常会让学员趁热打铁做一次小升级。第一轮升级很简单把读取文件、清洗数据、统计汇总、输出报告分别拆成独立的函数。比如这样def read_data(file_path): ... return lines def clean_data(lines): ... return orders, region_total, status_count def write_report(output_path, region_total, status_count, top5): ...拆完以后main()会变得非常短短到一眼能看出整个程序在做什么。这个练习的价值在于让学员第一次感受到“模块化”。不用等学到函数进阶第七天就可以埋下这颗种子把一个大问题切成几个小问题每一个小问题单独解决程序的可读性和可维护性立刻上一个台阶。很多学员写完函数版本以后感叹原来函数不是用来炫技的是让程序变整齐的。5.2 第二轮升级批量处理多个文件第二次升级稍微进阶一些假设现在有 3 个销售文件sales_01.csv、sales_02.csv、sales_03.csv每个文件结构相同要求把 3 个文件的数据合并统计输出一份总报告。这个任务的难点已经不是单纯的数据处理而是让程序学会“处理一个文件”再“处理下一个文件”。我给的方法是先用一个for循环遍历文件名列表然后在循环里调用已经封装好的清洗函数把三次统计结果累加到一个大字典里。用到的知识还是第七天已经练过的循环和字典但思路一下子跳到了“批量任务”的层面。这个升级我对学员说得很直白你以后上班接到的活不会只处理一个文件早晚要面对几十个几百个文件。第七天能提前体验一次“循环处理文件”后面学glob、学os.listdir的时候一点也不慌。5.3 给带新人的讲师三点建议如果你是讲师或者带人师傅第七天上机之后还有几点值得注意。第一一定要让学员自己敲完一遍代码千万不能发一份完整答案让他们对着抄那样看起来都会了其实一个 bug 都没见过。第二复盘时不要只讲“正确写法”要把学员犯过的错误匿名列出来逐条讲为什么错、怎么发现、怎么改反面教材有时候比标准答案更深刻。第三建议每次上机结束前留出 15 分钟让学员写三行笔记今天练了什么、卡在哪、下节课最想搞清楚什么。这个习惯对下一节课的设计非常有帮助也让学员自己看清进步轨迹。第七天真正有价值的东西其实是那种“被问题折磨过又最终解决”的体验。代码本身并不复杂甚至放到三个月以后回头看会觉得特别简单但第一次独立走完“看清需求、拆解步骤、写出代码、排除故障、输出结果”这一段路才是后面所有进阶内容的底气。踩过的坑越多手感越准这就是上机练习不可替代的原因。
返回列表