很多人学 Python 的时候,教程看了好几套,视频刷了几百集,一到自己动手就懵。打开编辑器,手指放在键盘上半天,不知道该写什么。这不是你笨,而是缺了“代码练习”这个环节里最核心的东西:一套能让自己真正写起来、又不会写到一半放弃的方法。
我做了十几年开发,带过不少新人,发现一个问题——凡是能在技术上真正稳住的人,不是那些刷题最多的,也不是看视频最快的,而是能把日常练习变成条件反射的人。Python 代码练习,听起来简单,实际上是个系统工程。它不只是写两段代码、跑通一个脚本,而是通过刻意训练,让你的大脑形成“看到需求→拆解逻辑→落到语法→跑出结果”的完整链路。这篇文章我不讲理论,不讲框架,只讲怎么把 Python 练习落到实处,让新手能坚持、老手能突破。
文章适合三类人:刚学完基础语法不知道下一步干啥的;刷了不少题但感觉实战还是发虚的;想带别人学 Python 但不知道怎么设计练习方案的。我会用一个完整的例子,带你走一遍“从题目到代码”的全过程,再聊聊练习中那些踩过的坑。
1. 为什么你练了很久,代码还是写不好
1.1 三个最常见的错误练习姿势
先对照一下,下面三种情况你中了几条。
第一种是“只抄不写”。跟着教程一个字一个字地把代码敲进去,跑通了就觉得自己会了,关掉编辑器第二天全忘光。这种练习本质上是打字训练,练的是手指肌肉,不是大脑逻辑。我见过一个同学,把一本入门书里所有示例代码都敲了三遍,问他一个简单的列表去重,还是写不出来。因为抄代码的时候,你的注意力全在“别打错字”上,根本分不出脑力去思考“为什么这里要用循环”。
第二种是“只刷题不思考”。今天做两道“两数之和”,明天做两道“反转字符串”,做完了对个答案,通过了就翻下一篇。这种练习的问题是碎片化,没有体系。你练了 50 道题,但每道题之间没有任何关联,大脑里的知识还是散的。就像一个人每天去健身房,今天举举这个,明天拉拉那个,从来不做训练计划,练三个月肌肉线条还是乱。
第三种是“跳过动手直接看答案”。题目拿到手,想了十分钟没思路,立刻打开题解。看完觉得自己懂了,实际上你只是“认识”了别人的解法,并没有建立自己的思考路径。下次遇到类似的题,你还是不会。记住一个判断标准:如果你不是闭着眼把代码写出来跑通,那这道题就等于没练。
1.2 练习的本质不是“写代码”,而是“做决策”
我说句可能不中听的话:代码练习练的不是语法,是决策能力。语法你查文档就会,但“这里该用列表还是字典”“这个循环边界怎么定”“这段逻辑要不要抽个函数”,这些才是写代码时真正消耗脑力的地方,也是练习真正要训练的部分。
拿做饭打比方。看菜谱等于看教程,你会背菜谱不等于会做饭。真正会做饭的人,是看到冰箱里剩了青椒、土豆、鸡蛋,脑子里立刻就能排出一个“先炒蛋还是先炒土豆”的顺序,知道什么时候开大火、什么时候转小火。这些决策能力,只能靠一次又一次真的下厨练出来。Python 代码练习也是一样,你面对的不只是“打印斐波那契数列”,而是通过这些小题目,反复训练自己面对需求时做拆解和决策的能力。题目本身并不重要,重要的是每一次练习都在强化你的“程序思维”回路。
2. 一套可持续的 Python 练习节奏
2.1 用“能一次写完”的标准来选题目
不少人练习坚持不下去,不是因为懒,而是因为题目选大了。上来就想写个爬虫、写个管理系统,结果写了一周还没跑通,信心被磨没了。
我的建议是:初学者选题目,守住一个标准——能在 20 分钟以内写完并跑通。这个标准很重要。时间太长,你的注意力会涣散;时间太短,又练不到东西。20 分钟刚好让你经历“读题→思考→写码→调试→跑通”的完整循环,又不会让你觉得枯燥。
推荐几类适合日常练的题目类型:
- 字符串处理类,比如统计一段文本里每个字母出现的次数、把下划线命名转成驼峰命名;
- 数据结构操作类,比如合并两个有序列表、用字典统计商品销量排名;
- 数学逻辑类,比如判断一个数是不是回文数、生成指定范围内的所有素数;
- 文件处理类,比如读一个文本文件,找出其中最长的一行。
这些题都不需要额外的第三方库,纯内置语法就能搞定,而且每一道都能练到“拆解+实现”两个环节。注意一点,同一类型的题目不要只做一道,至少做三道以上,你才能真正摸到这一类题的通法。
2.2 完整练习五步法:抄题、拆解、先写、比对、复盘
很多人的练习流程是“看题→写码→跑通→下一题”,这里面缺了两个步骤,导致练习效果打了五折。我建议每个人形成自己的固定节奏,我自己用的是五步法。
第一步“抄题”。不是让你把题目抄到本子上,而是用自己的话复述一遍题目的要求。你要能说出“输入是什么、输出是什么、中间有什么约束条件”。如果复述不清楚,说明你根本没看懂题,这时候别急着写代码。
第二步“拆解”。把一个大问题拆成三到五个小步骤。不需要写具体语法,用中文或者伪代码写下思路。你会发现,大部分写不出来的代码,都是死在“没拆好”这一步。
第三步“先写”。这个环节最重要的一条铁律:不管思路多笨,先写出一个能跑的版本再说。不要一上来就追求最优解,能跑通就是胜利。
第四步“比对”。跑通之后,去对比你脑海里的预期写法、或者去看看别的解法。不要只盯着一处不同,要看整体思路的差异。
第五步“复盘”。用一句话总结这道题让你学会了什么,记在你的练习笔记里。不要嫌这一步麻烦,这是把你从“做过题”提升到“会做题”的临门一脚。
这个五步法看起来啰嗦,但熟练之后,做一道简单题也就十五分钟左右。省掉最后两步,看似高效,实际上你练十道题的记忆留存率,不如别人认真练三道。
3. 实操拆解:把一道练习题做完整
3.1 一道真实的日常练习题
光讲方法不实操等于白讲,接下来我用一道我实际带新人时用过的题目,带你把整个练习过程走一遍。题目如下:
写一个函数,接收一段英文文本,返回出现次数最多的三个单词及其出现次数。要求忽略大小写,忽略标点符号,并列的单词按字典序排列。
这种题难度适中,特别适合用来练习“拆解能力”。它不涉及复杂的算法,但考察了字符串处理、数据结构选择、排序规则三个考点,刚好覆盖了 Python 基础里最常用的一块。
3.2 我的思考过程全记录
拿到题,我第一步不是写代码,而是先问自己三个问题。
第一个问题:输入长什么样?输入是一段英文文本,可能是单行也可能是多行,里面有大写有小写,有各种标点。
第二个问题:输出长什么样?输出是“单词-次数”的配对,而且只要前三个。
第三个问题:有哪些隐藏约束?“忽略大小写”,意味着要统一转成小写;“忽略标点符号”,意味着字符串里那些逗号、句号、感叹号都要去掉;“并列按字典序”,意味着排序的时候不能只按次数排,次数相同的时候要按单词本身的字母顺序排。
这三个问题想清楚,拆解就顺理成章了。我把整个过程分成四步:
- 清洗文本:转小写,把标点替换成空格;
- 切分单词:用
split()按空白把字符串切成列表; - 统计频次:用字典统计每个单词出现的次数;
- 排序取前三:先按次数降序,次数相同再按单词字母升序。
3.3 从第一版到第三版:代码是怎么一步一步变好的
很多新手一开始就追求写出完美代码,这是不可能的。我也是先写了个最笨的版本,再慢慢改进。
第一版,先把功能跑通,代码长这样:
import re def top_three_words(text): text = text.lower() text = re.sub(r'[^\w\s]', ' ', text) words = text.split() counter = {} for word in words: if word not in counter: counter[word] = 0 counter[word] += 1 sort_items = sorted(counter.items(), key=lambda x: (-x[1], x[0])) return sort_items[:3]这版能跑,但有个问题:re.sub(r'[^\w\s]', ' ', text)会把'也去掉,处理类似don't这种词的时候,会把它拆成don和t两个词。这个看需求怎么说,严格来说这里是有讨论空间的。
第二版,优化统计部分。我用了collections.Counter,代码短了不少:
from collections import Counter import re def top_three_words(text): text = re.sub(r'[^\w\s]', ' ', text.lower()) words = text.split() counter = Counter(words) top_items = sorted(counter.items(), key=lambda x: (-x[1], x[0])) return top_items[:3]第三版,我进一步思考:那个正则表达式是不是太粗暴了?如果文本里包含数字,\w会匹配数字,那数字串也会被当成单词。我又改成只保留字母和单引号,并且限制单引号不能是单词的开头和结尾。改完的版本更语义化,代码也更长了,但从需求角度看更准确。
这个演进过程本身就是练习的核心价值:你不需要第一版就写得多漂亮,但你一定要走到“对比、思考、改进”这一步。如果只停留在第一版,练习效果就少了七成。
4. 练习过程中高频报错与排查思路
4.1 三类必知的报错:语法错误、类型错误、逻辑错误
写代码没有不报错的,报错是正常的。关键是你要知道怎么面对它。我按频率把 Python 练习里最常见的报错分成三类。
第一类是语法错误(SyntaxError)。这个最简单,写着写着少个冒号、括号没配对、字符串引号没闭合,都会触发。解决办法也直接——看报错信息里指出的行号,光标定位在哪一行,就在那一行找问题。我见过新手在报错行下面找了半天,其实问题就出在“上一行末尾少了冒号”这种细节上。注意,Python 的报错行号有时候是“发现错误的位置”,不一定是“真正出错的位置”,所以排查的时候往回多看一行。
第二类是类型错误(TypeError)。比如把字符串和整数直接相加,或者对一个None调用列表方法。这类错误的根源往往是你对“这个变量到底是什么类型”没概念。排查思路是:在报错的那一行前面加一句print(type(变量名)),看看它的真实类型。很多新手一上来就纠结“为什么不对”,其实看一眼类型心里就有数了。
第三类是逻辑错误,这个最坑——程序不报错,但结果不对。有个经常犯的情况是“边界没处理好”,比如循环少了一次、判断条件用了>而应该是>=。对付逻辑错误,我的土办法是打印调试法:把中间步骤的值打印出来,一步一步对。比如上面的单词统计题,我先打印清洗后的字符串,再打印切分后的列表,最后再打印字典。哪一步不对,立刻就能定位。
4.2 读报错信息的三层技巧
很多新人遇到报错,第一反应是蒙,第二反应是把报错信息整段复制去搜。这两种都不太好。我教你三步读报错。
第一步,看最上面的异常类型。是IndexError、KeyError还是ValueError,光看类型就能知道大概方向。
第二步,看最后一行消息描述。Python 的报错信息其实写得挺直白的,比如list index out of range就是访问索引越界了,'NoneType' object is not subscriptable就是对一个None做了下标操作。
第三步,看 Traceback 中间部分,那里标着出错的文件名和行号。练习阶段代码都比较短,出现多次函数调用的情况也不多,所以基本靠“异常类型 + 行号”这两个信息就能定位问题。
我平时上课的时候经常说一句话:报错不是失败,是程序在跟你说话。它告诉你哪里不通,你顺着它的线索去找,这才是程序员解决问题的方式。你要训练自己“把报错当成线索而不是打击”的心态,这一步练好了,你写代码的胆子就大了,胆子一大,练得就多,练得多了自然就熟了。
4.3 调试的三个土办法
正式的项目里有断点调试器这类工具,但日常练习阶段,我推荐三个土办法,简单直接,而且非常有效。
第一个是print打印大法。没有比这个更合适的入门调试法。变量不确定就打印变量,逻辑不确定就打印中间结果。注意打印的时候加上标签,比如打印单词列表的时候写print("words:", words),不然打印一堆数据出来,你还要再回忆是谁是谁。
第二个是注释排查法。代码运行结果不对,你先注释掉一半代码,跑一下,看结果有没有变化,再用二分法慢慢缩小范围。这个办法对付逻辑错误特别管用。
第三个是构造最小复现用例。比如你用一段很长的文本测试,结果不对,这时候把文本精简成三五个单词,重新跑。小输入更容易让你看清逻辑的每一步对错,比盯着一大堆数据蒙头想高效得多。
这三个方法听着不高级,但确实是实战里最高频使用的排查思路。别觉得用print丢人,我写了十几年代码,遇到复杂的逻辑问题,第一反应还是先加一行打印看看中间状态。
5. 让练习成果沉淀下来:仓库与笔记
5.1 用 Git 管理你的练习代码
好多初学者有一个习惯:练习代码写完了,往本地文件夹一丢,再也不看。这样做的坏处是,你没法回看自己一周前写代码的思路变化,也没法直观地看到自己的进步。
我强烈建议每个练习者都建一个本地练习仓库,用 Git 做版本管理。不需要你现在就懂什么远程协作,只需要掌握最核心的四个动作:git init建仓、git add暂存、git commit提交、git log查看历史。每天练习完,提交一次,提交信息简单写明今天做了什么,比如“完成字符串处理类型的 3 道题”。
为什么要这么做?有两个好处是实打实的。第一,你能追踪自己的成长路径。一周之后回看自己第一天提交的代码,你会明显感觉到当时的代码写得有多“嫩”。这种直观的对比,比任何自我评价都更能增强坚持下去的信心。第二,逼你保持代码整洁。想到以后要提交到仓库,你就不会在文件里随便堆一堆乱七八糟的调试代码。
5.2 练习笔记到底该记什么
笔记不是抄题,也不是贴代码,而是记录“思维痕迹”。我自己的笔记分三个板块。
第一个板块,记错误。不是记“报了什么错”,而是记“我为什么报了这个错,以后怎么避免”。比如我记过这样一条:“今天把一个可变列表当作字典的键,报了TypeError: unhashable type: 'list'。字典的键必须不可变,以后遇到这个报错,先想想自己是不是用了列表当键。”
第二个板块,记套路。同一个类型的题做多了,你会总结出一些套路,把这些套路记下来。比如“字符串统一小写用.lower(),去标点用正则最方便”“统计词频首选Counter,它本身就是个字典,直接用items()转成元组列表方便排序”。这些套路是你最宝贵的解题资产。
第三个板块,记灵感。有时候写着写着,你会冒出一些想法:“这里好像能用一个字典推导式简化”“这个函数以后可以抽出来给别的脚本用”。这些灵感很短暂,不记下来转头就忘。记下来之后,你会发现自己的索引库里积累了很多可复用的代码片段。
一顿操作下来,你的练习仓库会变成一个可检索的“个人代码词典”。以后真要做项目了,翻自己的笔记,比去搜索引擎找靠谱得多,因为上面记录的都是你已经消化理解了的知识。
6. 再往下走:练习代码如何接轨真实项目
6.1 把练习功能包装成命令行小工具
练了一段时间之后,纯做题可能会有点无聊,这个时候该升级了。我推荐你做的一件事:把之前写过的练习代码,包装成一个可以在命令行里直接调用的工具。
举例来说,你写过那个统计高频单词的函数,可以稍加改造,让它在终端里直接用。写一个简单的参数解析,支持传入一个文件名,然后输出这个文件里出现频率最高的三个词。代码也就三四十行,但做出来的东西从“练习”变成了“工具”。
这个转变的逻辑在于:从“解题”到“满足真实需求”,中间隔着一层“工程化思维”。你要开始考虑命令行参数怎么设计、异常情况怎么处理、结果怎么格式化输出,这些都是真实的开发工作中每天都要面对的问题。而且,这个小工具做好了,是真的能用的。像我之前就把一个统计日志关键词的小脚本,包装成了自己日常排查数据时用的工具,写起来其实也就是练习题的量级。
6.2 给自己设置一个“项目式练习”周期
一直做小题目容易腻,一直做大型项目又容易受挫,更科学的方式是“小题目日常化,项目式周期性”。我建议你每学完一个阶段,给自己安排一个三天到一周能完成的小项目。
几个方向供参考:做一个通讯录管理程序,支持新增、删除、搜索联系人,数据存到本地文件;做一个简易的记账本,记录日常收支,按月份汇总统计;做一个命令行版的待办清单,支持添加、完成、查看过期任务。
这些项目规模都不大,但有一个共同点——它们需要你综合运用之前练过的所有知识点:函数、数据结构、文件操作、异常处理、简单的接口设计。这就像练武的人,日常扎马步是练基本功,定期打一次实战,把基本功串起来形成拳路。没有实战,基本功再扎实也用不出来。
关于“练到什么程度算学会”,我始终认为,不是看你会背多少方法,而是看你能不能在没有教程的情况下,独立把一个实际问题拆成代码实现出来。能做到这一点,你练的每一道题才真正在给你创造价值。
我个人最后再分享一个习惯:每次练习结束,把今天写过的代码往仓库里一推,然后在笔记里补两行字,写下“今天踩了一个什么坑”和“今天发现了一个什么好技巧”。这个动作我坚持了十年,我的代码能力就是靠这十年里点点滴滴的练习堆出来的。方法论说再多,不如你现在打开编辑器、找一道题、从头到尾写一遍。代码练习这件事,真正开始动手的人,已经赢过大多数人。