Python自学第二周练什么?四个小项目夯实基础语法 第二周练习这个标题乍一看平平无奇但在我看来它几乎是自学者的一道分水岭。很多朋友在第一天、第一周兴致勃勃看完变量、循环、函数觉得自己已经摸到了编程的大门结果到了第二周突然不知道该练什么、练到什么程度算完很多人就是在这个阶段慢慢放下了。这篇内容就是围绕我给自己带的三十天入门计划里的第二周练习展开的面向已经学完Python基础语法、但还没写过完整小项目的新手。这套练习不是什么高深算法而是通过几个贴近日常的小任务把循环、列表、字典、函数和文件读写这些核心语法焊死在你的脑子里。如果你正处于学了但不会用的状态照着做就行。1. 第二周练习的目标设计与任务拆解1.1 为什么第二周最容易放弃先说一个我观察到的现象第一周学语法每节课都有运行成功的正反馈今天学会if明天学会for每天都像在解锁新技能。到了第二周语法基本学完了但能力又不足以做像样的项目中间出现了一段巨大的真空期。你看别人的代码觉得我能看懂但是关掉教程让自己写就一个字都憋不出来。这就是经典的眼高手低阶段。更麻烦的是网上大多数教程在这一阶段给出的建议都是多练习但到底练什么、练到什么程度、怎么检查自己写得对不对没人说清楚。于是第二周练习就成了一个非常关键的承上启下环节它不需要你发明新东西只需要你把已经学过的语法组合起来完成几个小得不能再小的工具。这个过程本质上是在训练把问题翻译成代码的能力而这才是编程最核心的基本功。1.2 本周练习的设计思路我给第二周练习定了几条原则。第一所有题目必须能完整运行不做半成品第二每个练习里面至少要涉及一种数据结构列表、字典和一种控制流循环、条件第三题目来源于生活场景让你觉得做出来真能用的上而不是为了做题而做题。按照这三个原则我把练习拆成了四大块猜数字游戏练随机数、循环、条件判断、计数器。成绩统计工具练字典、列表嵌套、遍历与聚合计算。待办事项命令行工具练while循环、函数封装、用户输入处理、退出条件设计。词频统计练字符串处理、列表与字典的配合、排序。这四个练习的难度是平缓上升的。猜数字最简单核心就是两个数比较大小适合用来建立完整程序的感觉因为你在第一周写的都是代码片段很少见过一个带开始、过程、结束的完整程序。成绩统计开始引入数据集合你要反复思考怎么把零散的数据组织起来。待办事项工具则把视角从一次性执行拉到了持续运行加入函数封装和循环菜单。最后的词频统计算是一个综合实战把字符串、字典、排序全串起来了。有人可能会问第二周就写这些是不是太简单了我的回答是如果你能把这四个练习不看参考答案、独立写出来你对基础语法的掌握已经超过了大部分只刷过课的初学者。别贪多也别嫌简单这个阶段的质量远比数量重要。2. 核心知识点巩固与练习背后的原理2.1 循环与条件嵌套的逻辑训练第二周的练习表面上是写程序实际上是在训练你把逻辑链条掰开揉碎的能力。猜数字游戏里最简单的版本可能是这样写的import random target random.randint(1, 100) guess_count 0 while True: guess int(input(请输入你猜的数字1-100)) guess_count 1 if guess target: print(大了) elif guess target: print(小了) else: print(f恭喜你用了{guess_count}次猜对了) break这段代码看着不长但里面藏着几个关键设计决策。首先是while True加break的结构很多新手习惯用条件变量控制循环但在这个场景里猜中并且退出是唯一出口用无限循环加显式退出反而更清晰。其次是guess_count计数器它必须放在循环内部才能每次都累加这个每次循环要变化的变量思维正是之后写所有程序——比如统计、求和、累乘——的雏形。再往深一层说如果你给猜数字增加难度比如猜错超过7次就失败你会需要加一个失败条件这时你就得好好想想是继续让循环跑还是让循环条件变成guess_count 7这就逼着你理解循环条件的每一个细节。对比一下两种写法体会会很不一样。2.2 列表、字典与数据流思维我遇到过不少学生语法都会但一遇到一堆数据就蒙了。第二周练习专门安排了成绩统计这个任务就是要在这种混乱里建立数据结构思维。让我们看一个典型的需求输入三个学生的成绩每门课有语文、数学、英语最后要输出每个学生的平均分和每门课的平均分。面对这个问题第一反应可能是建三个列表、再建三个变量但很快你就发现数据对不上了。正确的做法应该先组织数据结构用列表装学生每个学生是字典字典里再装各科成绩。students [] for i in range(3): name input(f请输入第{i1}个学生的姓名) chinese int(input(语文成绩)) math int(input(数学成绩)) english int(input(英语成绩)) students.append({ name: name, chinese: chinese, math: math, english: english }) for stu in students: avg (stu[chinese] stu[math] stu[english]) / 3 print(f{stu[name]}的平均分是{avg:.1f}分) subjects [chinese, math, english] for sub in subjects: total sum([stu[sub] for stu in students]) print(f{sub}平均分{total / len(students):.1f})这个练习的核心不在代码量在于让你形成容器意识数据不是散落一地的变量而是应该被组织进合适的结构里。列表维护顺序字典靠名字取值两者嵌套还能表达更复杂的关系。这种能力以后要天天用所以第二周必须打好底子。2.3 函数封装的边界感到待办事项工具这一步我建议你用函数把功能块包起来一个show_menu()负责显示菜单一个add_task()负责添加任务一个show_tasks()负责展示列表主程序只负责循环调度。这样写的好处非常具体以加一个删除功能为例如果没有函数所有逻辑都堆在while循环里你需要在一大坨代码里找到删除操作的位置然后小心翼翼地插进去有了函数你只需要新写一个delete_task()然后在主循环菜单里加一个分支改动范围控制在几行以内。tasks [] def add_task(): task_name input(请输入任务内容) tasks.append({content: task_name, done: False}) print(已添加) def show_tasks(): if not tasks: print(暂无任务) return for idx, task in enumerate(tasks, start1): status 已完成 if task[done] else 未完成 print(f{idx}. {task[content]} [{status}]) while True: print(1. 添加任务 2. 查看任务 3. 退出) choice input(请选择) if choice 1: add_task() elif choice 2: show_tasks() elif choice 3: print(再见) break else: print(无效输入)这段代码里有一个特别值得玩味的点tasks列表定义在函数外面但函数里能直接访问和修改它。在Python里列表是可变对象函数内部调用它的append方法不会触发局部变量问题。很多新手在这里踩坑后就开始恐惧作用域其实不必你只需要记住一条经验法则尽量少在函数里直接改全局变量如果必须要改用返回值或者把数据作为参数传进来。这样的边界感一开始就要培养。3. 实操全过程从零完成三个小练习3.1 练习一猜数字游戏升级版猜数字的基础版我之前已经给出这里说一个升级版它能把循环和分支用得更加充分。规则是程序随机生成1到50之间的数字玩家最多猜8次每次猜完程序会提示大了或小了如果8次内猜中则胜利。额外加一个小要求如果玩家输入的不是数字程序不能崩溃而是提示重新输入。为什么加这个要求因为现实世界的用户不会按你的预期输入程序必须具备容错能力。处理非数字输入用到try...except这虽然不是第二周必须掌握的内容但在练习中用一次比专门学十遍都深刻。import random target random.randint(1, 50) MAX_TIMES 8 for attempt in range(1, MAX_TIMES 1): try: guess int(input(猜一个1到50之间的数字)) except ValueError: print(请输入数字本次不计入次数) continue if guess target: print(f你赢了第{attempt}次猜中答案是{target}) break elif guess target: print(大了) else: print(小了) else: print(f次数用完答案是{target}下次再试)我建议你亲手敲一遍而不是复制粘贴。敲的过程中你会注意到for...else这个结构它的含义是循环正常跑完没有遇到break就执行else。这个写法很Pythonic在搜索循环中经常用值得掌握。另外一个细节是输入错误时用continue而不是break这样就实现了不计入次数的逻辑。3.2 练习二学生成绩统计工具成绩统计我上面已经给过简化版本。这里我们再往前走一步允许用户反复输入输入q时停止输入然后输出所有学生的成绩排名和总分最高的学生名字。这里主要是训练字典和列表的配合以及灵活使用排序。students [] while True: name input(输入学生姓名输入q结束) if name.lower() q: break scores {} scores[语文] int(input(语文成绩)) scores[数学] int(input(数学成绩)) scores[英语] int(input(英语成绩)) students.append({name: name, scores: scores}) # 计算总分并排序 for stu in students: stu[total] sum(stu[scores].values()) ranked sorted(students, keylambda s: s[total], reverseTrue) print(成绩排名) for i, stu in enumerate(ranked, start1): print(f第{i}名{stu[name]}总分{stu[total]}分) if ranked: top ranked[0] print(f最高分{top[name]}总分{top[total]}分)lambda这种写法可能超出第二周的语法范围但你可以换成普通函数一样可以实现。关键是体会一个学生包含多维信息时字典嵌套的结构设计有多重要。等你的数据量变大你会感谢这个练习让你提前适应了这种组织方式。3.3 练习三待办事项命令行工具待办事项工具在上一节的函数演示里给过一个简版这里补上文件持久化。如果不把任务保存到文件里程序一退出任务就没了那就失去了工具的意义。我们需要在启动时读取文件在每次修改后写入文件。import json import os TODO_FILE tasks.json def load_tasks(): if not os.path.exists(TODO_FILE): return [] with open(TODO_FILE, r, encodingutf-8) as f: return json.load(f) def save_tasks(tasks): with open(TODO_FILE, w, encodingutf-8) as f: json.dump(tasks, f, ensure_asciiFalse, indent2) def add_task(tasks): content input(任务内容) tasks.append({content: content, done: False}) save_tasks(tasks) def complete_task(tasks): show_tasks(tasks) try: idx int(input(请输入要完成的任务编号)) - 1 tasks[idx][done] True save_tasks(tasks) except (ValueError, IndexError): print(编号无效) def show_tasks(tasks): if not tasks: print(暂无任务) return for i, task in enumerate(tasks, start1): mark 完成 if task[done] else 未完成 print(f{i}. {task[content]} [{mark}]) tasks load_tasks() while True: print(\n--- 待办事项 ---) print(1. 添加任务) print(2. 完成任务) print(3. 查看任务) print(4. 退出) choice input(请选择) if choice 1: add_task(tasks) elif choice 2: complete_task(tasks) elif choice 3: show_tasks(tasks) elif choice 4: print(已保存再见) break else: print(无效选择请重新输入)这次涉及的知识点比较多json模块的序列化和反序列化、os.path.exists判断文件是否存在、函数参数传递与修改。也许会有读者问怎么知道要用json其实不用刻意记你只需要知道文件可以存纯文本也可以存格式化文本。JSON是Python原生支持的数据格式存字典和列表最方便。这个工具做完之后你会突然发现之前的语法学习开始落地了——因为你在做一个关掉程序数据还在的东西这是很多正式软件的雏形。3.4 练习完成的检验标准与自测清单很多人在第二周会陷入练了但不知道练好没有的状态。我给自己制定了几个检验标准你可以直接抄作业对照无提示能力关上所有参考代码能独立写出上面三个练习的核心逻辑。改动应变能力故意改一个小需求比如把猜数字的范围从1到100改成1到1000或者给待办事项加上删除任务你能在10分钟内完成修改。问答能力被问到这段代码的while循环为什么不退出时你能清晰解释循环条件的真值变化。除了这三个标准我建议把练习过程中遇到的每一个报错都记录下来包括当时的代码和错误信息。第二周的报错其实就集中在那么几类后面我会细讲记录得多了你会发现自己排查错误的速度越来越快。这本身就是一种很重要的能力。4. 常见问题与排查技巧实录4.1 高频报错速查表第二周练习中我遇到的高频报错类型高度集中。把它们整理成一张表对你排查会很有帮助报错信息出现原因解决思路IndentationError: unexpected indent缩进不一致多按了一个Tab或空格统一用4个空格缩进不要混用Tab和空格IndexError: list index out of range访问列表不存在的下标检查循环是否越界打印len(列表)确认长度KeyError: xx字典中不存在该键检查键名是否拼错可以用dict.get(xx)代替ValueError: invalid literal for int()把非数字字符串转成了int用try...except捕获或先判断isdigit()NameError: name xx is not defined变量名拼错或作用域不对检查变量定义位置看是不是定义在某个函数内部TypeError: int object is not iterable对整数做了for循环确认循环对象是列表、字典等可迭代对象这张表里的错误我在带别人的过程中几乎每周都能看到一遍。尤其是缩进错误新手最容易犯而且它的问题是看不见摸不着——代码逻辑没错但就是跑不了。最笨也最有效的方法是删除代码中的所有缩进重新加一遍或者直接换一个编辑器强制显示空格和Tab的区别。4.2 一个典型的调试思路第二周练习里我觉得最值得分享的调试技巧是在关键节点打印中间结果。很多新手写代码写完全部逻辑才运行一次一看输出不对顿时不知所措。我的经验是输出不对的时候先把代码从头到尾读一遍在不确定的地方加print()把中间的变量打出来。比如猜数字程序你可以在循环开头打一行print(f当前猜的是{guess}目标数字是{target})这样你马上就能看出来是大小判断写反了还是数据取值问题。这招听起来土但实际上非常有效。现代IDE虽然有断点调试但打日志依然是排查问题最直接的手段因为它能让你看到程序在每一个时刻的现场状态而不是事后猜测。4.3 我踩过的坑和规避方法我自己在带班时发现一个极其隐蔽的坑在while True循环里用了input()如果程序提前退出或异常中断任务文件可能没保存。比如待办事项工具里用户直接关闭窗口没走4.退出这个分支新任务就全部丢失。我是怎么解决的每做一次修改就立即保存而不是等退出时才保存。这样即使程序崩溃最多丢一条记录不会清空全部数据。另外一个常见问题是中文路径和中文文件名导致编码报错。在Windows上踩过几次UnicodeDecodeError后我的习惯是所有文件操作统一加encodingutf-8参数所有代码文件头加一行# -*- coding: utf-8 -*-。虽然Python3默认就是UTF-8但显式声明能少很多麻烦尤其是在和别人协作不同系统时。5. 学习节奏与后续扩展建议5.1 七天时间怎么拆第二周练习不建议一天内做完更不建议一口气刷完然后晾一周。我的建议是第1天先自己动手写猜数字不参考任何答案。第2天优化猜数字加上错误输入处理和次数限制同时开始思考成绩统计的数据结构。第34天专心完成成绩统计重点锻炼字典和列表的嵌套使用。第56天做待办事项工具先不写文件用列表和循环实现基础功能再加文件持久化。第7天回顾四个练习把代码全部重写一遍不复制自己之前的版本。如果7天时间太赶我宁肯延长到10天也不建议压缩到3天。因为编程里的手感是需要时间的写代码的节奏感、对报错的敏感度都是用小时堆积起来的。压缩练习时间只会让你后面付出更大的代价。5.2 完成基础练习后的三个扩展方向第二周的练习做完了不要急着去学下一章新内容先把基础练习做几个扩展方向一给程序加记忆。比如猜数字的高分榜记录每次猜对所用的次数存进文件里下次启动显示历史最佳。这会用到文件读写和排序难度适中。方向二把命令行工具变成交互菜单。待办事项可以加删除任务按关键词搜索统计完成率每加一个功能你对函数和列表操作的理解就深一层。方向三用面向对象重构一遍。这个方向可能超前一些但如果你已经把待办事项写得滚瓜烂熟可以尝试把任务封装成类体验一下面向对象的第一感觉为后面的学习铺路。这三个方向任选一个足够你再练一周。练完以后你会明显感觉到看别人的代码不再只是能看懂而是开始能看出哪里写得不好、哪里可以改进这个阶段一旦到达你的学习就真正进入正向循环了。最后再分享一个我个人的小习惯第二周练习的代码不要急着删。留一份错漏百出的版本留一份最终完善的版本过一个月翻出来对比你会非常直观地看到自己进步了多少。这种可视化的成就感比任何激励都管用。