最近收到不少读者私信,说自己看完了一套 Python 入门视频,语法点好像都懂,但真正拿到一个需求时还是不知道从哪里下手,写出来的代码不是报错就是逻辑绕来绕去。如果你也遇到类似情况,我非常推荐你用“刷题”的方式把这个瓶颈补上。网上流传的“Python 330 道练习题,每天一练”就是一个很经典的练习路线,它能帮你把零散的语法知识拆成一个个可以动手验证的小任务,每天完成几道,比单纯看教程要扎实得多。接下来的内容,我会围绕这套练习思路,从环境准备、题目分类、典型代码拆解到常见报错排查,整理出一份完整的刷题指南。
1. 为什么要刷 Python 练习题?
1.1 看懂教程和会写代码是两回事
很多初学者容易陷入“视频看懂=学会了”的错觉。看老师写代码时,每一步都逻辑清晰,自己跟着敲一遍也能运行,可一旦关掉教程,面对一个空白的.py文件,大脑就很容易短路。这是因为“输入”和“输出”走的是两条不同的认知路径。
刷练习题的价值,就是强制你从一个“被动接收者”切换成“主动输出者”。题目给出了明确的目标,比如“统计一个字符串中每个字母出现的次数”,你必须自己去拆分问题、选择数据结构、写出语法正确的代码、调试运行结果。这个过程会真正训练你的编程思维,而不是让你的手停留在模仿层面。
1.2 练习题覆盖的编程核心能力
一套设计合理的 Python 练习题,通常不是让你机械地背题目,而是覆盖下面几类核心能力:
- 基础语法:变量、数据类型、运算符、条件判断、循环。
- 数据结构:列表、元组、字典、集合、字符串操作。
- 函数与模块:参数传递、返回值、默认参数、lambda、import。
- 文件操作:读写文本文件、处理 CSV、JSON 数据。
- 异常处理:捕获异常、抛出异常、自定义异常。
- 面向对象:类、对象、继承、封装、多态。
- 常用算法思维:排序、查找、递归、动态规划初体验。
- 综合实战:把多个知识点串联起来,完成一个小工具或小游戏。
“330 道题”这个数字本身并不是最重要的,重要的是它能帮你系统地把这些能力点过一遍,而不是东写一段、西写一段,最后什么都没沉淀下来。
1.3 每天练一点的节奏感
编程能力的提升不是一蹴而就的,每天保持节奏非常关键。与其周末突击五个小时,不如工作日每天晚上坚持 30 到 60 分钟,完成 5 到 10 道题。这样大脑有足够的时间去消化、遗忘、再回忆,反而记得更牢。这套“每天一练”的思路,就是你养成工程习惯的起点。
2. 环境准备与刷题姿势
“工欲善其事,必先利其器”。在开始刷题之前,先把 Python 开发环境准备好。这里我以一台 Windows 电脑为例,同时也会说明 macOS 和 Linux 下的一些差异。
2.1 安装 Python 并配置环境变量
如果你还没有安装 Python,请到 Python 官网下载对应系统的安装包。安装时有一个非常容易忽略的选项:Add Python to PATH。请务必勾选它,否则安装完成后,在命令行输入python很可能会提示“不是内部或外部命令”。
在命令行验证安装是否成功:
python --version如果输出类似Python 3.12.x,说明安装成功。如果你需要安装第三方库,还要确认 pip 是否可用:
pip --version如果提示pip不是命令,可以尝试:
python -m pip --version对于 macOS 和 Linux 用户,一般系统自带 Python 3,但版本可能比较旧,建议通过 Homebrew 或 apt 安装较新的 Python 3,并且优先使用python3命令。
2.2 使用 VSCode 配置 Python 环境
在刷题阶段,VSCode 是一个轻量又强大的选择。安装 VSCode 后,需要安装两个关键扩展:
- Python
- Pylance
安装完成后,按Ctrl+Shift+P(macOS 为Cmd+Shift+P),输入Python: Select Interpreter,选择你刚安装的 Python 解释器。这样右下角会显示当前解释器路径,代码补全和报错提示也会正常工作。
为了隔离不同项目的依赖,建议给刷题目录创建一个虚拟环境:
python -m venv venvWindows 下激活虚拟环境:
venv\Scripts\activatemacOS / Linux 下激活虚拟环境:
source venv/bin/activate激活后,命令提示符前面会出现(venv)字样。此时用 pip 安装的库只会进入当前项目,不会污染全局环境。
2.3 建议的刷题目录结构
不要把所有题目代码都堆在桌面上,建议按类型分目录。比如:
python_practice/ ├── day01_basic/ │ ├── 01_swap_values.py │ ├── 02_odd_even.py │ └── ... ├── day02_data_structure/ │ ├── 01_remove_duplicates.py │ └── ... ├── day03_function/ │ └── ... ├── day04_oop/ │ └── ... ├── day05_file_exception/ │ └── ... ├── day06_algorithm/ │ └── ... ├── day07_project/ │ └── ... ├── requirements.txt └── README.md这样做的好处是:后续复习时能快速找到对应知识点,而且可以写一个简单的README.md记录每天的刷题心得和易错点。
3. 330 道练习题如何分类?
以下分类方式是我根据常见的 Python 练习资源总结的,你可以把它看成一套“练习地图”。330 道题不需要一天做完,按节奏推进即可。
3.1 基础语法(约 100 题)
这部分主要围绕变量、数据类型、运算符、条件判断、循环来出题。典型题目包括:
- 交换两个变量的值。
- 判断一个数是奇数还是偶数。
- 打印九九乘法表。
- 计算 1 到 100 中所有偶数的和。
- 判断一个年份是否为闰年。
- 输出一个字符串的所有子串。
这些题目看似简单,但能帮助你打牢地基。尤其是循环嵌套和边界条件,很多初学者会在“范围多 1 少 1”的问题上反复犯错。
3.2 数据结构与内置方法(约 80 题)
当基础语法熟练后,就要开始熟悉 Python 最常用的内置数据结构。这部分题目会经常用到:
- 列表的切片、排序、翻转、去重。
- 元组的不可变性。
- 字典的键值对遍历、合并、默认值处理。
- 集合的交集、并集、差集。
- 字符串的格式化、分割、拼接、替换。
典型题目包括:
- 给定一个列表,去掉重复元素并保持原顺序。
- 统计一句话中每个单词出现的次数。
- 合并两个字典,相同键的值相加。
- 判断两个字符串是否为“同字母异序词”。
- 找出列表中出现次数最多的元素。
这些题目的解法往往不止一种,刷题时可以尝试先用最直观的方法写出来,再去思考有没有更 Pythonic 的写法。
3.3 函数、模块与异常处理(约 60 题)
函数是代码复用的基础。这部分题目会要求你定义函数、使用参数、返回结果,并尝试把代码拆分到多个模块中。常见题目包括:
- 编写函数计算斐波那契数列第 n 项。
- 编写函数判断一个数是否为素数。
- 编写函数,接收可变参数并返回平均值。
- 使用递归实现目录树形结构的打印。
- 使用
try / except处理除零异常和文件不存在异常。
值得注意的是,不要只关注函数能跑通,还要关注函数的“职责单一性”。如果一个函数既负责输入校验,又负责业务计算,还负责打印结果,后期维护起来会非常痛苦。
3.4 面向对象(约 40 题)
面向对象是 Python 进阶中绕不开的一块。这部分题目会要求你设计类,理解实例属性、类属性、实例方法、类方法、静态方法,以及继承和多态。典型题目包括:
- 设计一个
BankAccount类,支持存款、取款、查询余额。 - 设计一个
Student类,包含姓名、成绩,并能计算平均分。 - 设计一个
Shape基类,派生出Circle和Rectangle,分别计算面积。 - 实现一个简单的“提示与信息”装饰器,理解装饰器的语法糖。
新手初学面向对象时,最容易纠结的问题是“什么时候该用类,什么时候该用函数”。我的建议是:刷题阶段先按题目要求来,不要强行给所有功能都套上类。当一个场景里存在多个对象、多个属性、多个行为时,用类才更合适。
3.5 算法思维与综合项目(约 50 题)
最后一类题目会把前面所有知识综合起来,可能涉及排序算法、查找算法、递归、动态规划入门,以及一个小型项目。常见题目包括:
- 手动实现冒泡排序、选择排序、插入排序。
- 实现二分查找。
- 使用递归实现“汉诺塔”移动过程。
- 用 Python 实现一个简易通讯录,支持增删改查。
- 用文件读写实现一个“每日待办事项”记录工具。
- 使用
random模块实现猜数字游戏。
综合项目部分的题目不一定能在十分钟内完成,但它们的价值最高,因为你需要自己设计数据结构、拆分函数、处理异常、验证结果。这个过程最接近真实工作中的编码状态。
4. 典型练习题拆解:从题目到代码
只看分类还不够,下面我拆解几道典型的练习题,给出完整代码、运行结果和解释。你可以照着敲一遍,再改成别的条件来加深理解。
4.1 题目:交换两个变量的值(不引入临时变量)
这是一道很经典的入门题,看似简单,却能考察你对 Python 赋值的理解。
# 文件路径:day01_basic/01_swap_values.py a = 10 b = 20 print("交换前:", a, b) # 方法一:使用临时变量 temp = a a = b b = temp print("交换后(临时变量):", a, b) # 方法二:使用 Python 的多元赋值 a, b = b, a print("交换后(多元赋值):", a, b)运行结果:
交换前: 10 20 交换后(临时变量): 20 10 交换后(多元赋值): 10 20需要注意,第二种写法a, b = b, a在 Python 中是安全的,因为它会先计算右侧的元组(b, a),再依次赋值给左侧变量。这一点和其他一些语言不同,是很典型的 Pythonic 写法。
4.2 题目:列表去重并保持原顺序
很多初学者第一反应是用set去重,但set是无序的,会丢失原始顺序。比如:
nums = [3, 1, 2, 3, 4, 1, 5] print(set(nums))输出可能是{1, 2, 3, 4, 5},顺序和原列表不一定一致。如果题目要求保持原顺序,可以使用“字典键的有序性”或者手动遍历。
# 文件路径:day02_data_structure/02_remove_duplicates.py nums = [3, 1, 2, 3, 4, 1, 5] # 方法一:遍历 result = [] for num in nums: if num not in result: result.append(num) print(result) # 方法二:利用 dict.fromkeys result2 = list(dict.fromkeys(nums)) print(result2)运行结果都是:
[3, 1, 2, 4, 5]解释一下dict.fromkeys(nums)的原理:dict.fromkeys会创建一个字典,键来自nums,值是None。因为字典的键是唯一的,重复元素会被自动忽略,而且在 Python 3.7 之后,字典会保持键的插入顺序,所以再转换回列表时,顺序就保留下来了。
4.3 题目:统计文本文件中每个单词出现的次数
这个题目会用到文件读取、字符串分割、字典操作,非常综合。
假设有一个sample.txt文件,内容如下:
hello world python hello python python is great现在统计每个单词出现的次数:
# 文件路径:day05_file_exception/03_word_count.py from collections import Counter word_count = {} with open("sample.txt", "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue words = line.split() for word in words: word = word.lower() word_count[word] = word_count.get(word, 0) + 1 print(word_count) # 也可以直接用 Counter 简化 with open("sample.txt", "r", encoding="utf-8") as f: words = f.read().split() counter = Counter(words) print(counter)运行结果:
{'hello': 2, 'world': 1, 'python': 3, 'is': 1, 'great': 1} Counter({'python': 3, 'hello': 2, 'world': 1, 'is': 1, 'great': 1})这里有一个小坑:如果单词中存在标点符号,比如python,,直接split()会把逗号也算进单词里。更健壮的做法是使用正则表达式提取纯字母单词,但那是更高阶的内容,初学者可以先不做要求。
4.4 题目:设计一个“学生成绩”类
这是一个面向对象练习的典型题目。需求是:一个学生有姓名和若干门课成绩,可以添加成绩、计算平均分、判断是否及格。
# 文件路径:day04_oop/04_student.py class Student: def __init__(self, name): self.name = name self.scores = [] def add_score(self, score): if score < 0 or score > 100: raise ValueError("成绩必须在 0 到 100 之间") self.scores.append(score) def average(self): if not self.scores: return 0.0 return sum(self.scores) / len(self.scores) def is_pass(self, threshold=60): return self.average() >= threshold def __str__(self): return f"Student({self.name}, scores={self.scores}, avg={self.average():.2f})" if __name__ == "__main__": stu = Student("张三") stu.add_score(78) stu.add_score(85) stu.add_score(92) print(stu) print("平均分:", stu.average()) print("是否及格:", stu.is_pass())运行结果:
Student(张三, scores=[78, 85, 92], avg=85.00) 平均分: 85.0 是否及格: True这个例子体现了几个设计要点:
__init__负责初始化属性。add_score负责数据校验,不符合范围的数据直接抛异常。average只负责计算,不负责打印。is_pass使用默认参数,允许调用方自定义及格线。
把职责拆分清楚,代码会更容易测试和后续扩展。
4.5 题目:使用 asyncio 并发获取多个接口数据
当你已经掌握了基础语法和函数后,可以尝试让代码“跑得更快”。这里给出一个使用 Python 异步编程的入门示例,模拟并发请求多个接口数据。注意,实际请求外部接口时需要遵守接口提供方的使用规则,建议使用免费公开的 API 或本地服务进行练习。
# 文件路径:day06_algorithm/05_async_demo.py import asyncio async def fetch_data(name, delay): print(f"开始请求 {name}") await asyncio.sleep(delay) print(f"请求完成 {name},耗时 {delay} 秒") return f"{name} 的数据" async def main(): tasks = [ fetch_data("接口A", 2), fetch_data("接口B", 1), fetch_data("接口C", 3), ] results = await asyncio.gather(*tasks) print("所有结果:", results) if __name__ == "__main__": asyncio.run(main())运行结果:
开始请求 接口A 开始请求 接口B 开始请求 接口C 请求完成 接口B,耗时 1 秒 请求完成 接口A,耗时 2 秒 请求完成 接口C,耗时 3 秒 所有结果: ['接口A 的数据', '接口B 的数据', '接口C 的数据']可以看到,三个请求不是按顺序一个个等待,而是同时开始,总耗时约 3 秒,而不是 6 秒。这就是异步编程的核心优势:在等待 I/O 时,事件循环会切换到其他任务继续执行。刷题阶段能做到“看懂这个例子”即可,不需要立刻掌握所有细节,但它可以作为你后续学习 Python 异步编程的引子。
5. 刷题过程中的常见问题与排查思路
刷题一定会遇到报错。很多初学者一看到报错就慌,其实报错信息是程序给你的最好提示。下面整理几个高频问题。
5.1 程序报 NameError:name 'xxx' is not defined
这种错误通常是因为变量名拼写错误,或者变量在使用之后才赋值。看一下示例:
print(message) message = "hello"运行会报NameError。解决方法是把赋值语句放到使用之前:先定义变量,再使用。还可以检查是不是少导入了模块,比如用了math.sqrt却没有import math。
5.2 列表越界和循环边界问题
nums = [1, 2, 3] for i in range(len(nums) + 1): print(nums[i])运行会报IndexError: list index out of range。因为range(len(nums) + 1)会取到3,但列表最大下标是2。
排查步骤:
- 确认索引从 0 开始。
- 确认循环范围是
range(len(nums)),不是range(len(nums) + 1)。 - 如果用到
nums[i-1],考虑当i=0时是否会访问最后一个元素。
5.3 代码能运行但结果不对
这类问题最隐蔽,因为它不报错。建议采用“断言 + 手动走查”的方式:
- 把中间过程打印出来。
- 用一个非常小的测试用例手动计算。
- 使用
assert验证关键中间值。
例如:
def my_sum(nums): total = 0 for i in range(len(nums)): total += nums[i] return total assert my_sum([1, 2, 3]) == 6 print("测试通过")如果结果不对,就考虑是不是边界条件、除法取整、变量覆盖等问题。
5.4 环境相关的问题
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 命令行输入 python 提示“不是内部或外部命令” | 安装时未勾选 Add Python to PATH | 重新安装并勾选,或手动配置环境变量 |
| pip 安装库时提示“Connection error” | 网络问题或默认源不可达 | 使用国内镜像源,比如pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 库名 |
| VSCode 代码补全不生效 | 没有选择正确的解释器 | Ctrl+Shift+P选择 Python 解释器 |
| 运行后中文乱码 | 文件编码格式不一致 | 打开文件时使用encoding="utf-8",并确保文件本身是 UTF-8 编码 |
配置 Python 环境变量这个问题在 Windows 上比较常见,如果不想重新安装,也可以手动添加 Python 安装路径到系统的PATH变量中。不过对新手来说,重新安装并勾选选项是更稳妥的做法。
6. 刷题的最佳实践与工程建议
刷题不是完成任务,而是建立一套健康的编码习惯。下面这些建议能让你少走弯路。
6.1 先手动走查再写代码
拿到一道题,先不要急着敲键盘。在纸上或注释里写清输入、输出、步骤:
# 输入:一个整数列表 # 输出:一个排序后的新列表 # 步骤: # 1. 复制原列表 # 2. 使用 for 循环比较相邻元素 # 3. 交换顺序这个过程能极大减少逻辑错误。很多老手写代码之前也会先画草图或写伪代码,这是非常值得养成的习惯。
6.2 习惯使用函数封装和类型注解
即使是刷题,也建议把核心逻辑写进函数,而不是全部堆在全局代码中。这样后续可以方便地导入、测试和重复使用。类型注解能提高代码可读性,例如:
def add(a: int, b: int) -> int: return a + b类型注解不会影响运行,但 VSCode 和 Pylance 能据此给出更好的提示。
6.3 用 Git 管理练习题代码
刚开始刷题时,可以用一个 Git 仓库记录每天的代码。每天刷完之后提交一次,写清楚 commit message,比如:
git add . git commit -m "day03 完成函数练习题,修复素数判断边界问题"这样你能清晰看到自己的成长轨迹,也能在版本间对比代码差异。如果某个解法后来被证明有 bug,还可以回退到之前的状态。
6.4 把刷题代码升级成可测试代码
当你已经能稳定刷过基础题后,可以引入简单的pytest来测试自己的代码。以素数判断为例:
# 文件路径:day06_algorithm/test_is_prime.py def is_prime(n: int) -> bool: if n < 2: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True def test_is_prime(): assert is_prime(2) is True assert is_prime(9) is False assert is_prime(11) is True然后运行:
pytest test_is_prime.py这种测试思维会直接迁移到真实项目中,帮助你提前发现自己代码里的边界问题。
6.5 安全与授权意识
刷题过程中可能遇到涉及网络请求、文件删除、数据库操作的练习题。请务必只在你自己可控的测试环境里运行,不要拿生产数据或他人系统做实验。如果练习涉及爬虫类题目,需要遵守目标网站的robots协议和访问频率要求,不要对线上服务造成压力。编程能力的提升建立在合法合规的前提下,这一点从一开始就要牢记。
7. 总结与后续学习路线
如果你能按照“每天一练”的节奏做完这 330 道题,你会发现自己对 Python 编程的理解不再是零散的“见过”,而是真正具备了“能写出来”的底气。你对变量、循环、函数、列表、字典、类、文件操作这些核心概念会形成肌肉记忆,拿到一个新需求时,也会下意识地开始拆步骤、设计函数、考虑异常情况。
下一步可以尝试往更实际的方向延伸。比如你对数据分析感兴趣,可以继续学习pandas和matplotlib,用它们做数据分析与可视化;如果你想开发后端服务,可以学习FastAPI或Flask框架;如果你想写自动化脚本,可以研究requests、BeautifulSoup以及异步编程;如果希望把自己的小工具分享给别人,可以学习怎么把 Python 代码转成 exe 文件。
这一路没有玄学,靠的就是每天坚持写几道题,反复调试,错了就改,改完再总结。只要你把“330 道练习题”这份清单当成起点,而不是终点,你的 Python 编程能力一定会在这个过程中一点点长起来。接下来,挑一道你之前没做出来的题,打开编辑器,再试一次。