Python编程实战:25道练手题详解与核心技巧解析

📅 2026/8/17 10:33:55
Python编程实战:25道练手题详解与核心技巧解析
1. 项目概述为什么你需要这份Python练手题集如果你正在学习Python或者已经入门但感觉基础不牢、写代码时思路卡壳那你来对地方了。这份精心整理的25道Python练手题就是为你准备的“编程健身房”。它不是那种罗列一堆语法知识点的教科书而是直接把你拉到“实战场”上通过解决一个个具体、有趣的问题来真正内化Python的核心语法、数据结构与编程思想。我见过太多初学者看教程时觉得都懂一打开编辑器就大脑一片空白。问题出在哪里缺乏有效的、循序渐进的刻意练习。编程是一门实践的手艺光看不练永远学不会。这份题集的设计初衷就是填补“知道”和“会做”之间的鸿沟。题目覆盖了从基础数据类型操作、流程控制到函数、列表推导式、文件处理等关键知识点难度呈阶梯式上升。更重要的是每一道题我都附上了详细的解题思路和代码答案并会重点讲解其中的“坑点”和“优雅写法”。你可以先自己尝试卡住了再看答案和解析这个过程本身就是最高效的学习方式。无论你是准备面试、巩固基础还是想找点有趣的编程挑战这份题集都能让你在动手实践中感受到Python的简洁与强大逐步建立起解决实际问题的信心和能力。收藏起来每天刷几道一个月后你再看自己的代码会有脱胎换骨的感觉。2. 题目设计与解题思路全解析2.1 题目难度阶梯与知识点映射一份好的练习题集绝不是题目的简单堆砌。我这25道题是经过精心设计的遵循了“温故知新、循序渐进”的原则。我将它们大致分为四个阶段第一阶段基础热身第1-6题这个阶段的题目目标是唤醒你对Python最基本语法的肌肉记忆。重点考察变量、基本数据类型字符串、整数、运算符和最简单的条件判断。例如交换两个变量的值、判断闰年、数字求和等。这些题目看似简单但正是构建复杂程序的基石。我特别设计了一些“陷阱”比如闰年的判断规则能被4整除但不能被100整除或者能被400整除就是为了让你严谨地理解and和or的逻辑。第二阶段核心数据结构操作第7-14题列表、字典、元组和集合是Python的“四大金刚”。这个阶段的题目将深度操练这些数据结构。你会遇到列表排序区分sort()和sorted()、列表去重利用集合的特性、字典的合并与统计等经典问题。例如“统计字符串中每个字符出现的次数”一题就是字典的绝佳应用场景。通过这类练习你会深刻理解为什么说“选择合适的数据结构问题就解决了一半”。第三阶段函数与算法初探第15-20题当你能熟练操作数据后就需要学习如何用函数来组织代码并接触一些基础的算法思想。这个阶段会涉及递归如斐波那契数列、匿名函数lambda、map/filter/reduce等高阶函数以及简单的查找和排序算法思想如冒泡排序。编写一个判断素数的函数能让你练习函数的定义、参数传递和返回值同时理解算法效率只需遍历到平方根即可。第四阶段综合应用与文件处理第21-25题最后几道题模拟了更真实的微型项目场景。你会综合运用之前所学来处理文件读写、数据解析等任务。比如从文本文件中读取数据并计算统计信息或者实现一个简单的通讯录管理功能。这能让你体会到如何将零散的知识点串联起来解决一个完整的小问题为日后开发更复杂的程序打下基础。2.2 通用解题方法论与避坑指南在动手写代码之前掌握正确的解题思路比盲目敲键盘更重要。这里我分享一套通用的解题流程并指出新手最容易踩的“坑”。第一步彻底理解问题不要急于编码。仔细阅读题目描述用自己的话复述一遍需求。明确输入是什么格式、类型、范围输出又是什么。例如题目说“输入一个字符串”你要立刻想到字符串里会不会有空格会不会是空字符串这些边界情况决定了你代码的健壮性。第二步设计算法与数据结构在脑子里或纸上画一画解决问题的步骤。先用人能理解的逻辑描述出来。思考用什么数据结构来存储中间结果最方便是列表、字典还是集合这个过程能帮你厘清思路避免边写边改代码越写越乱。第三步编写代码与模块化将你的算法步骤转化为代码。遵循“先搭骨架再填血肉”的原则。先写出主干逻辑比如循环和判断结构然后再补充细节。一个重要的技巧是及时将一段功能独立的代码封装成函数。即使题目没要求这也是一种极好的练习能让你的代码更清晰、更易复用。第四步测试与调试用不同的输入测试你的代码特别是边界情况。比如对数字进行操作的题目要测试正数、负数、零处理列表的题目要测试空列表、只有一个元素的列表。Python的交互式环境REPL和print()函数是你最好的调试工具善用它们来查看程序运行过程中变量的值。避坑指南1可变对象的陷阱这是Python新手最容易出错的地方之一。列表和字典是可变对象。当你写new_list old_list时你并没有创建一个新的列表而是创建了一个指向同一块内存地址的新引用。修改new_list会导致old_list也一起被修改。正确的复制方法是使用list()构造函数、切片[:]或copy模块的deepcopy。避坑指南2迭代时修改容器在遍历一个列表或字典的同时又去删除或增加它的元素这会导致不可预知的行为比如跳过了某些元素或引发运行时错误。安全的做法是先创建一个你要修改元素的副本或者记录下需要删除的索引或键在迭代完成后再进行统一操作。3. 精选题目详解与代码实现下面我将挑选其中最具代表性的10道题目进行超详细的拆解。不仅给出答案更会剖析多种解法及其优劣并穿插大量实战中积累的技巧。3.1 第2题判断闰年题目输入一个年份判断它是否是闰年。详细解析 闰年的规则是能被4整除但不能被100整除或者能被400整除。很多新手会写成一系列嵌套的if-else其实用逻辑运算符一行就能优雅解决。代码实现def is_leap_year(year): 判断是否为闰年 :param year: 整数年份 :return: True 如果是闰年否则 False # 核心逻辑使用逻辑运算符组合条件 return (year % 4 0 and year % 100 ! 0) or (year % 400 0) # 测试用例 test_years [1900, 2000, 2024, 2025, 2100] for y in test_years: print(f{y}: {is_leap_year(y)})输出1900: False 2000: True 2024: True 2025: False 2100: False关键点运算符优先级and的优先级高于or所以(year % 4 0 and year % 100 ! 0)作为一个整体先计算。为了绝对清晰加上括号是个好习惯。函数化即使题目没要求也养成将功能封装成函数的习惯。这提高了代码的可读性和可测试性。测试一定要用多个边界值测试特别是像1900能被100整除但不能被400整除不是闰年和2000能被400整除是闰年这样的关键案例。3.2 第8题列表去重并保持原顺序题目给定一个可能包含重复元素的列表去除重复元素并尽可能保持剩余元素的原始顺序。详细解析 这是一个非常经典的面试题。最简单的方法是使用set但集合是无序的会打乱原顺序。我们的目标是既要去重又要保序。方法一使用字典Python 3.7从Python 3.7开始字典会保持键的插入顺序。我们可以利用这一点。def remove_duplicates_ordered(lst): 使用字典保持顺序去重 # 使用 fromkeys字典的键是唯一的且按首次出现顺序排列 return list(dict.fromkeys(lst)) # 示例 original_list [3, 2, 1, 2, 4, 3, 5] result remove_duplicates_ordered(original_list) print(f原列表: {original_list}) print(f去重后: {result})方法二使用循环判断通用方法如果考虑兼容更早的Python版本或者想明确展示算法逻辑可以使用一个辅助列表。def remove_duplicates_ordered_v2(lst): 使用循环和辅助列表去重 seen [] # 用于存放已出现的元素 for item in lst: if item not in seen: # 如果元素还没出现过 seen.append(item) # 添加到已见列表 return seen方法三使用列表推导式与集合简洁但需注意def remove_duplicates_ordered_v3(lst): 使用集合和列表推导式Python 3.6 可保序但原理依赖字典 seen set() # 利用集合的in操作是O(1)的特性提高效率 return [x for x in lst if not (x in seen or seen.add(x))]这个方法比较“炫技”。seen.add(x)总是返回None所以not (x in seen or seen.add(x))这个逻辑等价于如果x不在seen中就执行seen.add(x)并将其加入结果列表。它高效且简洁但可读性稍差。性能与选择对于中小型列表三种方法差异不大。dict.fromkeys()方法最Pythonic也最推荐。如果列表非常大方法三使用集合检查在平均情况下时间复杂度更优O(n)因为集合的成员检查是O(1)而列表的in操作是O(n)。核心技巧在面试或实际编码中优先选择list(dict.fromkeys(lst))因为它清晰、高效且能明确表达“利用键唯一性及顺序”的意图。3.3 第12题统计字符串字符频率题目输入一个字符串统计其中每个字符出现的次数。详细解析 这是字典的招牌应用场景。字符作为键出现的次数作为值。遍历字符串如果字符不在字典中就添加键并设值为1如果已在就将其值加1。基础实现def count_chars(text): 统计字符串中字符频率 char_count {} for char in text: # 方法1使用 if-else # if char in char_count: # char_count[char] 1 # else: # char_count[char] 1 # 方法2使用 get 方法更简洁 char_count[char] char_count.get(char, 0) 1 return char_count # 示例 sample_text hello world result count_chars(sample_text) print(result)使用collections.Counter进阶/生产环境推荐 Python标准库中的collections模块提供了Counter这个利器它就是为计数而生的。from collections import Counter def count_chars_counter(text): 使用 Counter 统计字符频率 return dict(Counter(text)) # 将Counter对象转为普通字典输出 result_counter count_chars_counter(hello world) print(result_counter)Counter不仅代码极其简洁还提供了most_common(n)等方法直接获取出现频率最高的前n个元素功能强大。扩展思考如果不想统计空格怎么办可以在遍历前用text.replace(‘ ‘, ‘’)或者遍历时加一个if char ! ‘ ‘:的判断。如果想忽略大小写怎么办可以在遍历时使用char.lower()。注意事项字典在Python 3.7之前是无序的如果你需要按字符出现顺序或频率排序输出可能需要使用collections.OrderedDict或对结果进行排序操作。3.4 第15题斐波那契数列递归与迭代题目生成斐波那契数列的第n项。斐波那契数列F(0)0, F(1)1, F(n)F(n-1)F(n-2) (n2)。详细解析 这道题是讲解递归和迭代思想以及算法效率的绝佳例子。方法一递归直观但低效def fibonacci_recursive(n): 递归实现斐波那契数列 警告n较大时性能极差 if n 1: return n return fibonacci_recursive(n-1) fibonacci_recursive(n-2)为什么低效以计算F(5)为例递归树如下F(5) / \ F(4) F(3) / \ / \ F(3) F(2) F(2) F(1) / \ / \ / \ F(2)F(1)F(1)F(0)F(1)F(0) / \ F(1) F(0)F(3)被计算了2次F(2)被计算了3次。随着n增大重复计算呈指数级增长时间复杂度约为O(2^n)完全不可接受。方法二迭代动态规划思想高效def fibonacci_iterative(n): 迭代实现斐波那契数列时间复杂度 O(n) if n 1: return n a, b 0, 1 # 分别代表 F(0) 和 F(1) for _ in range(2, n 1): a, b b, a b # 同时更新b 变为新的 F(i)a 变为旧的 b (即 F(i-1)) return b这种方法只遍历一次用两个变量a和b滚动更新存储前两项的值。时间复杂度是O(n)空间复杂度是O(1)非常高效。方法三带缓存的递归记忆化搜索如果你喜欢递归的简洁表达又不想忍受其低效可以使用“记忆化”技术。from functools import lru_cache lru_cache(maxsizeNone) # 使用LRU缓存装饰器自动缓存计算结果 def fibonacci_memoization(n): 带缓存的递归实现 if n 1: return n return fibonacci_memoization(n-1) fibonacci_memoization(n-2)lru_cache是Python标准库提供的装饰器它会自动存储函数调用的结果。当用相同的参数再次调用时直接返回缓存的结果避免了重复计算将时间复杂度从O(2^n)降到了O(n)。对比与选择学习递归概念使用方法一但要知道它的缺陷。实际应用无条件选择方法二迭代。它效率最高代码也清晰。理解优化技巧使用方法三它是递归算法优化的经典案例在很多动态规划问题中很有用。3.5 第18题使用filter和lambda筛选数据题目给定一个整数列表使用filter函数和lambda表达式筛选出其中的偶数。详细解析 这道题旨在练习函数式编程的基本概念。filter(func, iterable)函数接受一个函数func和一个可迭代对象返回一个迭代器其中包含所有使func返回True的元素。lambda则用于快速定义简单的匿名函数。代码实现numbers [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 使用 filter lambda even_numbers_iterator filter(lambda x: x % 2 0, numbers) # filter返回的是一个迭代器通常我们将其转换为列表 even_numbers_list list(even_numbers_iterator) print(f原列表: {numbers}) print(f偶数列表: {even_numbers_list})与传统循环对比# 等效的 for 循环实现 even_numbers_for [] for num in numbers: if num % 2 0: even_numbers_for.append(num)两种方式的比较filterlambda代码更简洁更具声明式编程风格描述“要什么”而不是“怎么做”。在处理数据管道或链式调用时特别有用。但可读性对于不熟悉函数式编程的人来说可能稍差。for循环更命令式步骤清晰对于复杂的判断逻辑更容易编写和调试。性能上两者在Python中差异不大列表推导式通常更快。更Pythonic的写法列表推导式其实对于这个简单需求列表推导式是更受Python社区推崇的写法even_numbers_comprehension [x for x in numbers if x % 2 0]列表推导式同样简洁且通常比filterlambda执行速度稍快因为它是在解释器层面优化过的语法结构。核心要点 这道题的目的是让你了解filter和lambda的用法。但在实际编码中如果只是简单的过滤优先考虑列表推导式。filter在需要将过滤函数作为参数传递例如过滤条件动态变化时更有优势。3.6 第21题冒泡排序算法实现题目手动实现冒泡排序算法对一个数字列表进行升序排序。详细解析 冒泡排序是排序算法的入门课它重复地遍历要排序的列表一次比较两个相邻元素如果它们的顺序错误就把它们交换过来。遍历列表的工作重复进行直到没有再需要交换的元素这意味着该列表已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。基础实现def bubble_sort_basic(arr): 基础冒泡排序 n len(arr) # 遍历所有数组元素 for i in range(n): # 最后 i 个元素已经就位无需再比较 for j in range(0, n - i - 1): # 如果当前元素大于下一个元素则交换 if arr[j] arr[j 1]: arr[j], arr[j 1] arr[j 1], arr[j] # Python 优雅的交换语法 return arr # 测试 unsorted_list [64, 34, 25, 12, 22, 11, 90] sorted_list bubble_sort_basic(unsorted_list.copy()) # 使用副本不改变原列表 print(f排序前: {unsorted_list}) print(f排序后: {sorted_list})优化版本提前终止基础版本即使列表已经有序也会完成所有轮次的遍历。我们可以加入一个标志位来优化。def bubble_sort_optimized(arr): 优化的冒泡排序提前终止 n len(arr) for i in range(n): swapped False # 标志位记录本轮是否发生交换 for j in range(0, n - i - 1): if arr[j] arr[j 1]: arr[j], arr[j 1] arr[j 1], arr[j] swapped True # 如果本轮没有发生任何交换说明列表已完全有序提前结束 if not swapped: break return arr这个优化对于近乎有序的列表能大幅提升效率。算法分析时间复杂度最坏和平均情况O(n²)当列表是逆序时。最好情况O(n)当列表已经有序时优化版本才能达到。空间复杂度O(1)属于原地排序。稳定性是稳定排序算法相等元素的相对位置不变。为什么还要学冒泡排序在实际开发中你几乎永远不会自己写冒泡排序Python内置的list.sort()或sorted()函数使用的是高效的Timsort算法。学习冒泡排序的价值在于理解排序的基本思想比较和交换。掌握算法分析的初步概念时间/空间复杂度。练习嵌套循环和条件判断。 把它当作一个思维体操而不是一个实用工具。3.7 第23题列表推导式生成杨辉三角题目使用列表推导式生成指定行数的杨辉三角。详细解析 杨辉三角是一个经典的数学图形每个数是它左上方和右上方的数的和。用编程生成它能很好地练习列表推导式和列表的嵌套操作。关键在于发现每一行与上一行的关系。思路分析第一行是[1]。第二行是[1, 1]。对于第i行i2除了首尾是1中间的第j个元素等于上一行的第j-1个元素加上第j个元素。即row[j] prev_row[j-1] prev_row[j]。代码实现def generate_pascal_triangle(num_rows): 生成杨辉三角 triangle [] # 用于存储整个三角形 for row_num in range(num_rows): # 每一行都是一个列表 # 第一行是 [1] # 第二行是 [1, 1] # 后续行首尾为1中间元素由上一行相邻两元素相加得到 row [1] # 每一行以1开头 if triangle: # 如果不是第一行 prev_row triangle[-1] # 获取上一行 # 使用列表推导式生成中间部分 # 对上一行进行滑动窗口求和prev_row[j] prev_row[j1] row.extend([prev_row[j] prev_row[j 1] for j in range(len(prev_row) - 1)]) row.append(1) # 每一行以1结尾 triangle.append(row) return triangle # 生成并打印前6行 rows 6 pascal_triangle generate_pascal_triangle(rows) for row in pascal_triangle: # 格式化打印使其居中显示更美观 print( .join(map(str, row)).center(rows * 3))纯列表推导式的“炫技”写法理解即可def generate_pascal_oneliner(n): 使用列表推导式的一行写法可读性较差仅供学习 return [[1 if j 0 or j i else (pascal[i-1][j-1] pascal[i-1][j]) for j in range(i1)] for i in range(n)]这种写法非常紧凑但难以理解和调试。在实际项目中强烈推荐使用第一种清晰易懂的写法。编程的首要目标是清晰表达意图而非追求极致的简短。练习价值 这道题综合运用了循环、列表操作、条件判断和列表推导式。它教会你如何将复杂的数学规律转化为清晰的程序逻辑并且展示了如何用代码构建一个结构化的数据列表的列表。3.8 第25题简单文件单词统计器题目读取一个文本文件统计文件中每个单词出现的次数并将结果按出现频率从高到低输出。详细解析 这是一个微型的综合项目涉及文件I/O、字符串处理、数据统计和排序。它模拟了数据分析中的一个常见任务。实现步骤拆解读取文件使用with open(...) as f安全地打开文件并读取全部内容。文本预处理将内容转换为小写使统计不区分大小写去除标点符号。分割单词使用字符串的split()方法按空白字符分割成单词列表。统计频率使用collections.Counter进行计数。排序输出使用Counter的most_common()方法直接获取排序后的结果。代码实现import re from collections import Counter def count_words_in_file(filepath): 统计文本文件中单词频率 :param filepath: 文本文件路径 :return: 按频率降序排列的 (单词 次数) 列表 try: with open(filepath, r, encodingutf-8) as file: text file.read() except FileNotFoundError: print(f错误文件 {filepath} 未找到。) return [] except IOError as e: print(f读取文件时发生错误: {e}) return [] # 文本预处理转小写使用正则表达式移除非字母数字字符保留连字符等可根据需求调整 # 这里\w匹配单词字符字母、数字、下划线^表示取反即替换掉所有非单词字符为空格 cleaned_text re.sub(r[^\w\s], , text.lower()) # 分割单词 words cleaned_text.split() # 使用Counter统计 word_counts Counter(words) # 返回最常见的单词及其计数 return word_counts.most_common() # 假设有一个名为 ‘sample.txt’ 的文件 results count_words_in_file(sample.txt) # 打印前10个最常见的单词 print(单词统计结果频率从高到低:) for word, count in results[:10]: print(f{word}: {count}) # 如果你想输出所有单词 # for word, count in results: # print(f{word}: {count})关键点与注意事项文件编码始终指定文件编码如utf-8这是避免中文等非ASCII字符乱码的关键。使用with语句可以确保文件被正确关闭。异常处理文件操作可能失败文件不存在、无权限等添加try-except块使程序更健壮。文本清洗正则表达式re.sub(r[^\w\s]’, ‘ ‘, text)是核心。它匹配所有非单词字符、非空白字符即标点符号并将其替换为空格。这是一个简化的清洗根据实际文本如包含缩写Im或带连字符的单词well-known可能需要更复杂的规则。性能考虑对于大文件一次性读取全部内容file.read()可能占用大量内存。可以改为逐行读取处理。Counter.most_common()这个方法返回一个元素为(item, count)的列表已经按计数从大到小排好序非常方便。这个小小的程序串联了多个知识点是一个很好的练手项目。你可以在此基础上扩展比如忽略常见无意义词停用词、绘制词云图等。4. 常见问题与排查技巧实录在练习这些题目时你肯定会遇到各种错误和疑惑。下面我总结了一些最常见的问题及其解决方法这可能是比题目答案更有价值的经验。4.1 缩进错误IndentationError这是Python新手的第一道坎。Python用缩进来定义代码块混用空格和Tab键或者缩进级别不一致都会导致此错误。错误示例def my_func(): print(Hello) # 这里没有缩进解决方案使用统一的缩进方式强烈建议只使用空格并设置你的代码编辑器将Tab键自动转换为4个空格这是PEP 8官方建议。检查编辑器设置在VS Code、PyCharm等编辑器中查看右下角确保显示的是“Spaces: 4”而不是“Tab Size: 4”。利用编辑器的显示功能开启“显示空白字符”功能这样空格和Tab会以不同的点或箭头显示出来一目了然。4.2 变量作用域混淆在函数内部修改全局变量或者不理解局部变量和全局变量的区别会导致意想不到的结果。错误示例count 0 def increment(): count 1 # UnboundLocalError: local variable count referenced before assignment increment()在函数内部count 1被解释为对局部变量count赋值但此时局部变量count还未被定义。解决方案明确使用global关键字通常不推荐因为它破坏了函数的封装性def increment(): global count count 1通过参数传递和返回值推荐做法def increment(num): return num 1 count increment(count)使用可变对象如果要修改的是全局的列表或字典直接操作其元素是可行的因为你不是在给变量本身重新赋值。my_list [1, 2, 3] def append_to_list(): my_list.append(4) # 这是可以的修改的是列表对象的内容4.3 列表修改时的“幽灵”错误在遍历列表的同时修改其长度增删元素是另一个经典错误源。错误示例words [hello, world, python, is, great] for word in words: if len(word) 4: words.remove(word) # 危险在迭代中修改列表 print(words) # 结果可能不符合预期比如 ‘is’ 可能没有被删除当删除一个元素后列表长度和索引都变了但迭代器仍按原索引前进可能导致某些元素被跳过。解决方案创建新列表最安全、最清晰new_words [word for word in words if len(word) 4]遍历副本修改原列表for word in words[:]: # 使用切片 words[:] 创建副本进行遍历 if len(word) 4: words.remove(word)反向遍历适用于删除操作for i in range(len(words)-1, -1, -1): # 从后往前遍历 if len(words[i]) 4: del words[i]反向遍历时删除元素不会影响前面未遍历到的元素的索引。4.4 字符串与数字类型转换错误从输入如input()函数获取的数据默认是字符串类型直接用于数学运算会导致TypeError。错误示例user_input input(请输入一个数字: ) result user_input * 2 # 如果输入5结果是‘55’而不是10解决方案明确转换使用int(),float()进行转换。try: number int(user_input) result number * 2 except ValueError: print(输入的不是有效整数)使用try-except捕获异常用户输入是不可靠的必须做好异常处理防止程序崩溃。4.5 函数默认参数的可变陷阱这是一个高级但常见的坑。如果函数的默认参数是一个可变对象如列表、字典那么这个默认参数在函数定义时就被创建了并且在整个程序运行期间都是同一个对象。错误示例def add_item(item, my_list[]): my_list.append(item) return my_list print(add_item(1)) # 输出 [1] print(add_item(2)) # 输出 [1, 2]而不是预期的 [2]解决方案永远不要使用可变对象作为函数参数的默认值。正确的做法是使用None然后在函数内部进行判断和初始化。def add_item_correct(item, my_listNone): if my_list is None: my_list [] my_list.append(item) return my_list print(add_item_correct(1)) # 输出 [1] print(add_item_correct(2)) # 输出 [2]4.6 调试技巧print大法好与pdb入门当程序行为不符合预期时不要干瞪眼要主动调试。print()调试法在关键位置打印变量的值。这是最简单粗暴有效的方法。def complex_calculation(data): print(f[DEBUG] 输入数据: {data}) # 打印输入 intermediate step1(data) print(f[DEBUG] 第一步结果: {intermediate}) # 打印中间结果 result step2(intermediate) print(f[DEBUG] 最终结果: {result}) # 打印最终结果 return result使用f-stringPython 3.6可以方便地格式化输出。调试完后记得删除或注释掉这些打印语句。使用断言assert在代码中插入检查点确保某些条件为真。def divide(a, b): assert b ! 0, 除数不能为零 return a / b如果b为0程序会抛出AssertionError并停止帮助你快速定位问题。断言通常用于开发阶段在生产环境中可能会被禁用。使用调试器pdb对于复杂问题交互式调试器是终极武器。在怀疑有问题的代码行前插入import pdb; pdb.set_trace()运行程序时会在此处进入调试模式。你可以n(next): 执行下一行。s(step): 进入函数内部。c(continue): 继续执行直到下一个断点。p 变量名: 打印变量值。l(list): 查看当前代码位置。q(quit): 退出调试。 虽然一开始可能不习惯但学会使用调试器能极大提升你解决复杂Bug的效率。坚持把这25道题自己动手敲一遍遇到错误就对照上面的排查技巧解决你的Python实战能力一定会突飞猛进。编程没有捷径就是不断地思考、敲代码、调试、再思考。这份题集和解析就是你的训练手册现在打开你的编辑器开始练习吧。