Python入门练习一核心解析:素数、回文、列表去重与调试技巧 1. 这个练习到底在练什么先说结论这是 Python 入门阶段最常见的第一套综合练习看起来只是几道基础题但它们把“语法、逻辑、调试、代码习惯”全串在了一起。我当年做这套练习时觉得“这也太简单了”结果真正动笔才发现能从零写对、写得干净、还能经得起追问的没几个。如果你正在学 Python或者刚开始做这类作业这篇文章就是按照我当时踩坑的路径整理的尽量把每一步背后的原因也讲清楚。这套“练习一”通常包含这些典型题目求某个范围内的素数质数并输出判断一个字符串是否为回文列表去重并保持顺序用循环实现阶乘或斐波那契数列写一个简单的命令行交互程序。1.1 从需求到代码练习一的核心考点这类练习表面上考的是“会写函数”“会用循环”“会处理字符串和列表”实际上考的是三件更底层的事。第一能不能把自然语言转换成程序流程。比如“输出 100 以内的所有素数”这句话看着明白但要写出代码你得先把它拆成“对 2 到 100 的每个数判断它是不是素数如果是就 print 出来”。这个转化的能力才是编程入门真正要练的。很多同学卡住不是不会写 if 和 for而是根本不知道怎么把题目的话变成步骤。第二边界条件意识。判断素数你考虑 2 了吗考虑 1 了吗判断回文空字符串怎么处理列表去重顺序要不要保留这些边界条件恰恰是一段代码健壮与否的分水岭。第三排错的基本功。报错之后是直接复制到搜索引擎还是先看报错信息指向的行号和错误类型我见过太多同学一看到IndentationError就懵其实错误信息已经把问题说得明明白白只是没耐心读。1.2 练习设计的逻辑为什么都是这些老题目每套“练习一”大同小异你会发现无非是循环、判断、字符串、列表这几样的组合。这其实是故意安排的。顺序题阶乘、斐波那契练的是“用循环重复执行同一段逻辑”这是程序的核心能力之一判断类题目素数、回文练的是“条件分支 布尔逻辑”这是程序做决策的基础结构类题目列表去重、排序练的是“数据的存储与变换”这直接关系到后面所有真实项目的数据处理。一套练习做下来相当于把你接触到的 Python 基础语法全部用实战走了一遍。有个理解误区要提前说这些题目不是让你背代码的。我当时就是吃了这个亏看了一遍解法觉得很简单以为自己会了结果合上书自己写连range(2, n)的2从哪来都忘了。练习一真正的意义是让你在“看懂了”和“写得出”之间建立起那座桥而这座桥只能通过亲手敲代码来搭。2. 动手前的基础准备写代码之前环境这块如果没弄对后面会有各种莫名其妙的问题而且你会分不清是环境问题还是自己代码的问题。2.1 环境与编辑器的选择Python 版本这块建议直接用 3.10 以上的版本。早些年还有人和你说 Python 2 和 Python 3 的区别现在完全没必要纠结了直接上 3。编辑器方面不用迷信复杂的 IDEVisual Studio Code 加上 Python 插件或者直接用一个带语法高亮的编辑器都行。刚开始写练习越轻量越好我见过不少同学打开某个大型 IDE 光配置就配了一上午练习一个字没写。一个建议练手阶段就用自己的终端跑脚本先别急着用 Jupyter Notebook。Notebook 的“一格一格执行”模式看着方便但它会隐藏掉一些脚本从上到下顺序执行的过程容易让你养成“跑不通就往前面补一个单元格再跑”的坏习惯不利于建立一次运行出结果的整体思维。2.2 写代码前先做三件事第一件事把题目用白话说出来。比如说“计算 n 的阶乘”用自己的话说就是“从 1 一直乘到 n”。这句话写出来代码结构基本就出来了。第二件事在草稿纸上画几个例子。不要一上来就写代码先手工算几个结果。比如5! 120或者fib(7) 13。这样你写完代码能用这些手工结果去验证而不是靠“感觉好像对了”。第三件事想清楚输入输出到底是什么。题目说“输入一个整数 n”那 n 的取值范围有没有限制是用户手动输入还是测试用例自动传入输出格式是每个元素一行还是用空格分隔这些问题想清楚了能省掉大量测试返工。3. 核心题目拆解与代码实现下面挑三个我练习一里印象最深的题目来详细拆解。代码都是当时我自己跑过的版本保留了基础的样子也保留了一些值得注意的写法。3.1 题目一输出 n 以内的所有素数这道题我当年第一遍写出来的版本是这样的def is_prime(n): if n 2: return False for i in range(2, n): if n % i 0: return False return True limit 100 result [] for num in range(2, limit 1): if is_prime(num): result.append(num) print(result)先说为什么is_prime要先排除n 2。因为 0 和 1 都不是素数这是定义问题不写的话1会被判成素数逻辑就错了。这也印证了前面说的边界条件的重要性。再说为什么循环里是range(2, n)。素数的定义是“只能被 1 和它本身整除”所以要检查从 2 到 n-1 这些数如果有任何一个能整除 n就说明 n 不是素数。这里有个小优化可以先不急着学但我提一句到sqrt(n)就停就够了。因为如果 n 有一个大于平方根的因子那一定有一个小于平方根的因子成对出现。这个优化在数字小的时候看不出来但 n 到十万百万级别时差距是天壤之别。练习阶段可以先不优化但心里要留个印象。跑出来的结果大概是这样[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]3.2 题目二判断回文字符串回文就是正着读和反着读一样的字符串比如abcba。这个题的解法有很多我当年最直观的想法是“把字符串反转看原串和反转串是否相等”。def is_palindrome(s): s s.replace( , ).lower() return s s[::-1]这里面有两个细节值得注意。第一s[::-1]是 Python 里反转字符串最直接的方式。它的本质是切片[开始:结束:步长]步长写成-1表示从末尾往前取。第二字符串两端可能有空格大小写也可能不同。比如A man a plan a canal Panama这种经典回文句子如果不处理空格和大小写判断就会出错。所以我先replace( , )去空格再.lower()统一转小写。这就是在练“对现实数据的敏感度”——题目没明说但实际使用中这些情况很常见。不过s s[::-1]这种写法虽然简洁但面试或作业里有时候会被追问“如果不能用切片怎么办”。这时候可以用双指针法def is_palindrome(s): left, right 0, len(s) - 1 while left right: if s[left] ! s[right]: return False left 1 right - 1 return True双指针法的思想是一头一尾逐个比较遇到不等就直接判False直到两个指针相遇。这个思路不依赖任何语言特性在任何编程语言里都能写体现了真正的算法理解。把两个版本的差异想明白能力提升会很明显。3.3 题目三列表去重并保持顺序题目要求有一个列表可能有重复元素去掉重复项并且保持第一次出现的相对顺序。我第一反应用的是集合set因为它天生就是去重的data [3, 5, 2, 5, 3, 8, 9, 2] unique list(set(data)) print(unique)结果是[2, 3, 5, 8, 9]这样的顺序但问题是集合是无序的结果顺序完全不可控题目要求保持原顺序这就违反了要求。所以更稳妥的写法是遍历原列表把没见过的元素加进去data [3, 5, 2, 5, 3, 8, 9, 2] unique [] for item in data: if item not in unique: unique.append(item) print(unique)这个写法逻辑上没错但效率上有问题if item not in unique会逐个扫描unique列表数据量一大就会很慢。更好的做法是用一个集合来记录“已经见过哪些元素”列表来记录“最终结果”data [3, 5, 2, 5, 3, 8, 9, 2] seen set() unique [] for item in data: if item not in seen: seen.add(item) unique.append(item) print(unique)这样既保持了顺序又利用了集合查找快的特性。Python 里这种“两套结构配合”的思路很常见值得花时间消化。还有个情况要注意如果元素里面既有整数又有字符串比如[1, 1, 2]在 Python 里1和1不是同一个元素所以两个都会保留。如果业务上认为它们相等那就要额外写归一化逻辑。这又是边界条件的一种体现。4. 踩坑实录与排查技巧这一节是重点因为我当时几乎所有报错都遇到了而且每一个都要花好久才明白问题在哪。4.1 缩进问题Python 的隐形炸弹Python 用缩进来表示代码块这和其他语言用大括号完全不同。第一次遇到IndentationError: unexpected indent时我盯着代码看了半天怎么看不出来“意外缩进”在哪。后来才知道可能只是在前面多打了一个空格或 Tab整个代码块就乱了。经验教训用 4 个空格做一级缩进全程别混用 Tab 和空格。编辑器里把 Tab 自动替换成空格这个功能打开。另外缩进不只是“好看”它是语法的一部分。你写的代码缩进层级如果有跳变比如从二级缩进直接跳到四级缩进Python 会直接报错。4.2 类型混用的坑input()返回的是字符串第一道题可能就挂在这。你用input(请输入一个数字: )接收用户输入然后直接拿去做乘法结果报错TypeError: cant multiply sequence by non-int of type str。因为input()永远返回字符串如果想做数学运算必须先转换类型n int(input(请输入一个整数: ))但这里又有个新坑如果用户输入的不是数字比如输入了abcint()会抛ValueError。作业阶段可以不处理但心里要知道有这种可能性。事实上装一个简单的捕获结构就能更稳try: n int(input(请输入一个整数: )) except ValueError: print(输入的不是有效数字) exit()这行代码在小练习里可能用不太上但往后写稍微正式一点的项目几乎每个输入都要考虑这种“用户乱输”的情况。提前养成这个习惯后面会少吃很多苦。4.3 循环边界range的终点永远取不到range(1, 100)会生成 1 到 99不包含 100。这个规则每个初学者都要栽一次。我当时写“求1到100的和”写了range(1, 100)结果每回少算一个 100。这个问题的根源在于range(start, end)的语义是“左闭右开”即包含 start不包含 end。这是 Python 里的一个普遍约定切片也是这样。理解了这一点下次写“1 到 n”的循环就知道应该写range(1, n 1)。还有个更隐蔽的坑循环变量在循环结束后会保留最后一个值。Python 的for i in range(5)结束后i的值是 4不是 5。如果后面又有代码依赖i很容易算错。所以关键逻辑不要依赖循环变量结束后的值如果你确实需要它自己用一个变量显式保存。4.4 输出格式不对明明结果对但判题就是不过很多练习系统会对输出格式做严格比对。题目要求“每个素数占一行”你用了print(prime)可能就多打了一个空格要求“用逗号分隔”你用了print( .join(...))就会格式错误。我经历过一次最无语的情况题目要求输出 “sum5050” 这种带固定前缀的格式结果我只输出了数字答案判错。从那之后我对题目的“输出示例”都是逐字符看的包括空格、换行、大小写。这条对需要交代码到自动评测系统的同学尤其重要。5. 一些能帮你少走弯路的小习惯这些习惯可能不会让练习一立刻拿高分但它们能让你在往后写更复杂的代码时轻松很多。5.1 写伪代码把思路先落下来再翻译成语法写代码前先写一遍伪代码比如对 i 从 2 到 100 如果 i 是素数 把 i 放进结果列表 打印结果列表伪代码不需要语法正确它只需要把你的思路固定下来。写的时候你会发现很多“我以为我想清楚了”的细节其实还没想明白。伪代码一旦顺畅正式代码基本就是逐行翻译的事。5.2 学会阅读报错信息报错信息不是给机器看的是给人看的。Traceback (most recent call last)下面那一部分会明确指出哪个文件哪一行出了问题。有一次我写判断素数的函数报错报在第 7 行我前 6 行怎么都看不出问题后来逐行数才发现是函数里一个变量名拼错了。有个实用技巧看到报错先找到File ..., line N这个 N 是行号然后去代码里看那一行95% 的问题都能当场定位。不要一上来就整个文件重查那样既慢又容易漏。5.3 手算答案来验证代码上面的题目每个都有固定答案比如10! 3628800fib(10) 55。先手算出结果再跑代码对比这比“看着输出感觉没问题”靠谱得多。我那时候习惯在草稿纸上来几张测试表写完代码直接对着测试。这是一个非常朴素的测试方法虽然不是自动化测试但对练习一这个阶段来说效率极高。6. 交作业前的自查清单最后的最后把家里的代码来回检查一遍。这套清单是给“练习一”这类小项目的也适用于今后任何代码提交。6.1 代码格式自查缩进是否统一为 4 个空格变量命名是否清晰别用a、b、c这种毫无信息量的名字is_prime、item、unique这种看到就知道含义的更好。有没有残留的调试用print比如那些临时打的print(debug: str(i))函数有没有写好文档字符串或至少一行注释我见过一份作业功能全对但整个代码没有一个注释变量名全是x、y、z老师最后也只是给了及格分。这其实挺可惜的因为写注释和命名清晰不是浪费时间它们是在帮你和其他人“长期维护”这段代码。6.2 功能自查极端输入有没有考虑比如空列表、0、负数、非常大但合理边界内的数字。输出格式是不是和题目示例完全一致手动跑几组输入对比预期结果。6.3 我的一点个人体会做练习一最大的收获其实不是那几道题的答案而是“从看题目到写代码之间那一段思考过程的熟练度”。我练完之后最大的变化是看到问题不再害怕会条件反射地去想“输入是什么、输出是什么、中间经过哪些步骤、有哪些边界条件”。这种思维定式才是练习一真正希望留给你的东西。如果这套练习你是一次性写完并且测试通过那说明入门很顺利可以继续学函数进阶、文件读写和异常处理了。如果中途磕磕绊绊那也很正常我当时至少在“列表去重并保持顺序”这道题上纠结了一个晚上。多写几遍把每一个思路都在笔记里记下来再回头看你会发现自己比第一天强了很多。