很多Python初学者在学完基础语法后,常常感觉“一看就会,一写就废”。面对实际需求时,大脑一片空白,不知从何下手。这正是因为缺乏系统性的编程思维训练和足够的代码实践。本文为你精心整理了一套覆盖Python核心知识点的330道练习题,并附上详细解析。通过“每天一练”的节奏,你将彻底打通从理论到实践的任督二脉,告别“纸上谈兵”,真正掌握用Python解决实际问题的能力。无论你是准备面试、备战考试,还是想夯实基础,这套练习都能让你事半功倍。
1. Python编程练习的核心价值与学习路径
1.1 为什么“刷题”是编程学习的必经之路
编程语言的学习,与学习游泳或驾驶类似,理解原理只是第一步,大量的重复练习才是形成肌肉记忆、内化知识的关键。单纯阅读教程或观看视频,只能让你“知道”某个语法点,而通过解决具体问题,你才能“理解”其应用场景和边界条件。练习题的价值在于:
- 巩固语法:将分散的语法点(如循环、条件判断、函数定义)串联起来,在具体语境中加深记忆。
- 训练思维:学习如何将复杂的现实问题,分解为计算机可以执行的步骤(即算法),这是编程的核心能力。
- 熟悉标准库:Python拥有强大的标准库(如
os,json,datetime,collections),通过练习可以熟悉它们的常用API。 - 排查错误(Debug):在练习中你会遇到各种错误(
SyntaxError,IndexError,TypeError等),解决它们的过程就是提升调试能力的过程。 - 积累代码片段:许多练习题的解法和技巧(如列表推导式、字典排序、文件操作)可以直接复用到实际项目中。
1.2 如何高效使用这330道练习题
盲目刷题效果有限,遵循科学的方法才能最大化学习收益:
- 循序渐进:本套练习已按难度和知识点分类。建议从基础题开始,逐步挑战进阶题目。
- 先思后码:看到题目后,不要立刻写代码。先在纸上或脑子里梳理逻辑,画出流程图或写出伪代码。
- 独立完成:遇到难题时,给自己足够的思考时间。实在无法解决,再参考答案解析,并理解其思路,而非简单复制代码。
- 举一反三:完成一道题后,尝试修改题目条件(例如,将“求最大值”改为“求第二大值”),或者用不同的方法(如用循环代替递归)重新实现。
- 整理与复盘:建立自己的“错题本”或代码库,记录经典的解法、易错点和心得。
1.3 环境准备与工具推荐
工欲善其事,必先利其器。一个顺手的开发环境能极大提升练习效率。
- Python环境:确保已安装Python。推荐使用Python 3.8及以上版本。在命令行输入
python --version或python3 --version检查。 - 集成开发环境(IDE):
- PyCharm:功能强大的专业IDE,适合中大型项目,调试功能完善。
- VS Code:轻量级且高度可定制,通过安装Python插件可以获得近乎IDE的体验,是当前非常流行的选择。
- Jupyter Notebook:特别适合数据分析、机器学习领域的交互式编程和练习,能分块运行代码并即时查看结果。
- 代码编辑器:对于纯练习,Sublime Text、Vim等也足够使用。
- 必备工具:学会使用Python内置的
help()函数、dir()函数,以及在线官方文档,这是你最好的老师。
下面,我们将从最基础的练习题开始,逐步深入,涵盖变量、数据类型、控制流、函数、文件操作、面向对象等核心主题。
2. 基础语法与数据类型练习(第1-70题)
这一部分是基石,目标是让你对Python的基本构建块了如指掌。
2.1 变量、输入输出与算术运算
目标:掌握如何与程序交互,进行基本计算。
练习题示例与解析:
题目:编写一个程序,接收用户输入的两个数字,计算并输出它们的和、差、积、商(保留两位小数)。
# 示例代码 num1 = float(input("请输入第一个数字: ")) num2 = float(input("请输入第二个数字: ")) sum_result = num1 + num2 difference = num1 - num2 product = num1 * num2 # 处理除零错误 if num2 != 0: quotient = round(num1 / num2, 2) else: quotient = "无穷大 (除数不能为0)" print(f"和: {sum_result}") print(f"差: {difference}") print(f"积: {product}") print(f"商: {quotient}")关键点:
input()函数获取的是字符串,必须用float()或int()转换。- 使用
round(number, ndigits)进行四舍五入。 - 除法操作前务必检查除数是否为零,这是基本的健壮性考虑。
f-string(格式化字符串字面值)是Python 3.6+推荐的首选格式化方法,简洁高效。
题目:将华氏温度转换为摄氏温度。公式:
C = (F - 32) / 1.8。fahrenheit = float(input("请输入华氏温度: ")) celsius = (fahrenheit - 32) / 1.8 print(f"{fahrenheit} 华氏度等于 {celsius:.2f} 摄氏度") # :.2f 表示保留两位小数
2.2 字符串操作
目标:熟练掌握字符串的切片、拼接、查找、替换等操作。
练习题示例与解析: 3.题目:输入一个字符串,分别输出其长度、反转后的字符串、全部大写和全部小写形式。 ```python my_string = input("请输入一个字符串: ")
length = len(my_string) reversed_str = my_string[::-1] # 利用切片实现反转,是Pythonic的写法 upper_str = my_string.upper() lower_str = my_string.lower() print(f"长度: {length}") print(f"反转: {reversed_str}") print(f"大写: {upper_str}") print(f"小写: {lower_str}") ``` **关键点**: - `len()`是内置函数,用于获取序列长度。 - 字符串切片`[start:stop:step]`功能强大,`[::-1]`是经典的反转技巧。 - `str.upper()`和`str.lower()`返回新字符串,原字符串不变。- 题目:检查一个字符串是否为回文(正读反读都一样),如“level”。
关键点:定义函数def is_palindrome(s): # 预处理:忽略大小写和空格(根据题目要求调整) s = s.lower().replace(" ", "") return s == s[::-1] test_str = "A man a plan a canal Panama" if is_palindrome(test_str): print(f"'{test_str}' 是回文") else: print(f"'{test_str}' 不是回文")def来封装逻辑,提高代码复用性。
2.3 列表与元组
目标:理解可变序列(列表)和不可变序列(元组)的特性和常用方法。
练习题示例与解析: 5.题目:创建一个包含10个随机整数的列表(范围1-100),找出其中的最大值、最小值和总和。 ```python import random
# 生成随机列表 random_list = [random.randint(1, 100) for _ in range(10)] print(f"生成的列表: {random_list}") max_value = max(random_list) min_value = min(random_list) sum_value = sum(random_list) print(f"最大值: {max_value}") print(f"最小值: {min_value}") print(f"总和: {sum_value}") ``` **关键点**: - 使用列表推导式`[expression for item in iterable]`可以简洁地生成列表。 - 善用内置函数`max()`, `min()`, `sum()`。- 题目:合并两个列表并去重。
关键点:集合(list1 = [1, 2, 3, 4, 5] list2 = [4, 5, 6, 7, 8] # 方法1: 使用集合(无序) merged_set = set(list1) | set(list2) merged_list_from_set = list(merged_set) print(f"使用集合合并去重: {merged_list_from_set}") # 方法2: 使用循环(保持顺序,以list1顺序优先) merged_list = list1[:] # 复制list1 for item in list2: if item not in merged_list: merged_list.append(item) print(f"使用循环合并去重(保持顺序): {merged_list}")set)是处理去重问题的利器,但会丢失原顺序。需要保持顺序时,需用循环判断。
2.4 字典与集合
目标:掌握键值对映射和唯一元素集合的应用。
练习题示例与解析: 7.题目:统计一段英文文本中每个单词出现的次数(忽略大小写和标点)。 ```python text = "Hello world, hello Python! Python is great. World is big."
# 1. 清洗文本:转小写,替换标点为空格 import string translator = str.maketrans('', '', string.punctuation) # 创建删除标点的映射表 cleaned_text = text.lower().translate(translator) # 2. 分割单词 words = cleaned_text.split() # 3. 使用字典统计 word_count = {} for word in words: word_count[word] = word_count.get(word, 0) + 1 # get方法安全获取,不存在则返回0 print("单词统计结果:") for word, count in word_count.items(): print(f" {word}: {count}") ``` **关键点**: - `str.maketrans()`和`translate()`是处理字符串替换/删除的高效方法。 - `dict.get(key, default)`是安全访问字典值的最佳实践,避免`KeyError`。 - `string.punctuation`包含了所有英文标点符号。- 题目:找出两个列表中的共同元素(交集)。
关键点:对于查找、去重、集合运算,list_a = [1, 2, 3, 4, 5] list_b = [4, 5, 6, 7, 8] # 方法1: 使用集合 common_elements_set = set(list_a) & set(list_b) print(f"使用集合求交集: {common_elements_set}") # 方法2: 使用列表推导式 common_elements_list = [x for x in list_a if x in list_b] print(f"使用列表推导式求交集: {common_elements_list}")set的性能远高于列表。
3. 流程控制与函数练习(第71-150题)
掌握如何控制程序执行流程,并学会用函数组织代码。
3.1 条件判断与循环
目标:熟练运用if-elif-else和for/while循环解决逻辑问题。
练习题示例与解析: 9.题目:判断一个年份是否为闰年。闰年规则:能被4整除但不能被100整除,或者能被400整除。 ```python def is_leap_year(year): if (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0): return True else: return False
# 更简洁的写法 def is_leap_year_concise(year): return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0) test_year = 2024 print(f"{test_year}年是闰年吗? {is_leap_year(test_year)}") ``` **关键点**:理解闰年的逻辑条件,并用布尔表达式准确表达。- 题目:打印九九乘法表。
关键点:嵌套循环的理解,以及for i in range(1, 10): # 外层循环控制行 for j in range(1, i + 1): # 内层循环控制列,到i为止 # 使用f-string和制表符\t对齐 print(f"{j} x {i} = {i*j:2d}", end="\t") # :2d 保证两位宽度右对齐 print() # 换行print函数end参数的使用来控制输出格式。
3.2 函数定义与使用
目标:学会定义函数、使用参数(位置参数、默认参数、可变参数)、返回值。
练习题示例与解析: 11.题目:编写一个函数,计算任意数量的数字的平均值。 ```python def calculate_average(*args): """计算任意数量数字的平均值 *args: 可变位置参数,接收一个元组 """ if not args: # 处理空参数的情况 return 0 return sum(args) / len(args)
# 测试 print(calculate_average(1, 2, 3, 4, 5)) # 输出 3.0 print(calculate_average(10, 20)) # 输出 15.0 print(calculate_average()) # 输出 0 ``` **关键点**: - `*args`用于接收任意数量的位置参数,在函数内部它是一个元组。 - 函数应具备健壮性,这里处理了参数为空的情况。- 题目:编写一个函数,接收一个字典,返回一个键值互换的新字典。假设原字典的值都是不可变类型(如字符串、数字)。
关键点:遍历字典使用def invert_dict(original_dict): """反转字典的键和值""" inverted = {} for key, value in original_dict.items(): # 注意:如果原字典有重复的值,反转后会丢失键(后面的覆盖前面的) inverted[value] = key return inverted my_dict = {'a': 1, 'b': 2, 'c': 3} inverted_dict = invert_dict(my_dict) print(f"原字典: {my_dict}") print(f"反转后: {inverted_dict}").items()方法。需注意值重复会导致信息丢失,进阶版本可以用列表存储相同值对应的所有键。
3.3 递归与算法初探
目标:理解递归思想,解决阶乘、斐波那契数列等经典问题。
练习题示例与解析: 13.题目:使用递归函数计算阶乘n! = n * (n-1) * ... * 1。 ```python def factorial_recursive(n): if n < 0: return None # 阶乘未定义 elif n == 0 or n == 1: # 递归基线条件 return 1 else: return n * factorial_recursive(n - 1) # 递归调用
# 测试 for i in range(6): print(f"{i}! = {factorial_recursive(i)}") # 注意:递归深度限制,对于大的n会报错 RecursionError # 可以使用循环迭代来避免 def factorial_iterative(n): result = 1 for i in range(2, n + 1): result *= i return result ``` **关键点**:递归函数必须有一个或多个**基线条件**(停止条件),否则会无限递归。对于深度大的问题,递归可能引发性能问题或栈溢出。- 题目:生成斐波那契数列的前n项。数列定义:F(0)=0, F(1)=1, F(n)=F(n-1)+F(n-2)。
关键点:这是迭代解法,效率远高于朴素的递归解法。递归解法存在大量的重复计算,可用“记忆化”技术优化。def fibonacci_sequence(n): """返回斐波那契数列的前n项列表""" if n <= 0: return [] elif n == 1: return [0] elif n == 2: return [0, 1] fib_list = [0, 1] for i in range(2, n): next_value = fib_list[i-1] + fib_list[i-2] fib_list.append(next_value) return fib_list print(fibonacci_sequence(10)) # 输出 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
4. 文件操作与异常处理练习(第151-220题)
学习如何与外部文件交互,并优雅地处理程序运行中可能出现的错误。
4.1 文件读写
目标:掌握open()函数、读写模式、with语句以及json/csv等常见格式的处理。
练习题示例与解析: 15.题目:将一个字符串列表逐行写入到一个文本文件中,然后读取该文件并打印内容。 ```python # 准备数据 lines_to_write = [ "这是第一行。", "Hello, World!", "Python文件操作练习。", "最后一行。" ]
# 写入文件 filename = "sample.txt" with open(filename, 'w', encoding='utf-8') as file: for line in lines_to_write: file.write(line + '\n') # 每行末尾添加换行符 print(f"内容已写入文件: {filename}") # 读取文件 print("\n读取文件内容:") with open(filename, 'r', encoding='utf-8') as file: # 方法1: 一次性读取所有行 # content = file.read() # print(content) # 方法2: 逐行读取(推荐,节省内存) for line_num, line in enumerate(file, start=1): print(f"第{line_num}行: {line.rstrip()}") # rstrip() 去掉右侧换行符 ``` **关键点**: - **始终使用`with`语句**:它能确保文件被正确关闭,即使发生异常。 - **指定编码**:使用`encoding='utf-8'`避免中文乱码。 - **注意换行符**:写入时手动添加`\n`,读取时用`rstrip()`去除。- 题目:从一个CSV文件(假设内容为“姓名,年龄,城市”)中读取数据,并计算平均年龄。
关键点:import csv # 假设 data.csv 内容如下: # 姓名,年龄,城市 # 张三,25,北京 # 李四,30,上海 # 王五,28,广州 filename = 'data.csv' total_age = 0 count = 0 with open(filename, 'r', encoding='utf-8') as csvfile: reader = csv.DictReader(csvfile) # 使用DictReader,将每行转为字典 for row in reader: age = int(row['年龄']) # 访问‘年龄’列 total_age += age count += 1 print(f"姓名: {row['姓名']}, 年龄: {age}, 城市: {row['城市']}") if count > 0: average_age = total_age / count print(f"\n总人数: {count}, 平均年龄: {average_age:.2f}") else: print("文件为空或格式错误。")csv模块简化了CSV文件的读写。DictReader通过列标题访问数据,代码可读性更强。
4.2 异常处理
目标:使用try-except-else-finally结构捕获和处理异常,提高程序鲁棒性。
练习题示例与解析: 17.题目:编写一个安全的数字除法程序,处理除零错误和输入非数字的错误。 ```python def safe_divide(): """安全地进行除法运算""" try: num1 = float(input("请输入被除数: ")) num2 = float(input("请输入除数: ")) result = num1 / num2 except ValueError: print("错误:输入的不是有效数字!") return None except ZeroDivisionError: print("错误:除数不能为零!") return None except Exception as e: # 捕获其他未预料到的异常 print(f"发生未知错误: {type(e).name} - {e}") return None else: # 如果没有异常发生,执行这里的代码 print(f"{num1} / {num2} = {result}") return result finally: # 无论是否发生异常,都会执行这里的代码(常用于清理资源) print("除法运算尝试结束。")
# 运行函数 safe_divide() ``` **关键点**: - **精确捕获**:优先捕获具体的异常类型(如`ValueError`, `ZeroDivisionError`),最后用通用的`Exception`兜底。 - **`else`子句**:当`try`块中的代码成功执行后,会执行`else`块。这有助于将正常逻辑与异常处理分离。 - **`finally`子句**:无论是否发生异常都会执行,用于释放资源(如关闭文件、网络连接)。- 题目:尝试打开一个可能不存在的文件,如果不存在则创建它。
关键点:filename = 'my_data.json' try: with open(filename, 'r', encoding='utf-8') as f: content = f.read() print(f"文件存在,内容为:\n{content}") except FileNotFoundError: print(f"文件 '{filename}' 不存在,将创建它。") # 创建文件并写入初始内容 with open(filename, 'w', encoding='utf-8') as f: initial_data = '{"message": "这是一个新创建的文件。"}' f.write(initial_data) print("文件创建成功。") except IOError as e: print(f"读写文件时发生I/O错误: {e}")FileNotFoundError是IOError的子类,用于精确处理文件找不到的情况。
5. 面向对象编程与模块练习(第221-280题)
理解类、对象、继承、多态等概念,并学会组织模块化代码。
5.1 类与对象
目标:掌握类的定义、__init__方法、实例属性和方法。
练习题示例与解析: 19.题目:定义一个Student类,包含姓名、学号、成绩列表属性,以及计算平均分、添加成绩等方法。 ```python class Student: """学生类"""
def __init__(self, name, student_id): """初始化学生属性""" self.name = name self.student_id = student_id self.grades = [] # 成绩列表初始化为空 def add_grade(self, grade): """添加一门课的成绩""" if 0 <= grade <= 100: self.grades.append(grade) print(f"为 {self.name} 添加成绩: {grade}") else: print(f"无效成绩: {grade},成绩应在0-100之间。") def calculate_average(self): """计算平均分""" if not self.grades: return 0.0 return sum(self.grades) / len(self.grades) def display_info(self): """显示学生信息""" avg = self.calculate_average() print(f"学生: {self.name} (学号: {self.student_id})") print(f" 成绩列表: {self.grades}") print(f" 平均分: {avg:.2f}") # 创建对象并使用 stu1 = Student("张三", "S001") stu1.add_grade(85) stu1.add_grade(92) stu1.add_grade(78) stu1.display_info() stu2 = Student("李四", "S002") stu2.add_grade(88) stu2.add_grade(95) stu2.display_info() ``` **关键点**: - `__init__`是构造方法,在创建对象时自动调用。 - `self`代表类的实例本身,用于访问实例的属性和方法。 - 方法内部应对输入参数进行有效性检查(如成绩范围)。5.2 继承与多态
目标:理解类之间的“is-a”关系,实现代码复用。
练习题示例与解析: 20.题目:定义一个Shape(形状)基类,派生出Rectangle(矩形)和Circle(圆形)子类,实现计算面积和周长的多态方法。 ```python import math
class Shape: """形状基类""" def area(self): """计算面积(由子类实现)""" raise NotImplementedError("子类必须实现 area() 方法") def perimeter(self): """计算周长(由子类实现)""" raise NotImplementedError("子类必须实现 perimeter() 方法") def display(self): """显示信息""" print(f"形状: {self.__class__.__name__}") print(f" 面积: {self.area():.2f}") print(f" 周长: {self.perimeter():.2f}") class Rectangle(Shape): """矩形类""" def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height) class Circle(Shape): """圆形类""" def __init__(self, radius): self.radius = radius def area(self): return math.pi * self.radius ** 2 def perimeter(self): return 2 * math.pi * self.radius # 测试多态 shapes = [ Rectangle(5, 3), Circle(4), Rectangle(2, 2), Circle(1) ] for shape in shapes: shape.display() print("-" * 20) ``` **关键点**: - 基类`Shape`定义了接口(`area`, `perimeter`),但具体实现交由子类。 - `NotImplementedError`用于明确提示子类需要重写方法。 - 多态性允许我们使用统一的接口(`shape.area()`)操作不同的对象,而无需关心其具体类型。5.3 模块与包
目标:学会将代码组织到不同的模块和包中,并使用import导入。
练习题示例与解析: 21.题目:创建一个自定义的数学工具模块mymath.py,包含一些常用函数,然后在主程序中导入并使用。 ```python # 文件: mymath.py """自定义数学工具模块"""
def add(a, b): """返回两个数的和""" return a + b def multiply(a, b): """返回两个数的积""" return a * b def factorial(n): """返回n的阶乘(迭代实现)""" result = 1 for i in range(2, n + 1): result *= i return result def is_prime(n): """判断一个数是否为质数""" if n <= 1: return False for i in range(2, int(n ** 0.5) + 1): if n % i == 0: return False return True # 文件: main.py """主程序,导入并使用自定义模块""" # 导入整个模块 import mymath print("使用 mymath.add:", mymath.add(10, 20)) print("使用 mymath.multiply:", mymath.multiply(5, 6)) print("5的阶乘是:", mymath.factorial(5)) print("17是质数吗?", mymath.is_prime(17)) # 也可以导入特定函数 from mymath import factorial, is_prime print("\n使用直接导入的函数:") print("factorial(4) =", factorial(4)) ``` **关键点**: - 模块是一个`.py`文件,包是一个包含`__init__.py`文件的目录。 - `import module` 导入整个模块,使用时需加模块名前缀。 - `from module import function` 导入特定函数,可以直接使用函数名。 - 良好的模块化设计能使项目结构清晰,便于维护和复用。6. 进阶实战与综合练习(第281-330题)
将前面所学知识融会贯通,解决更复杂、更贴近实际的问题。
6.1 数据处理与分析
目标:使用Python处理和分析结构化或半结构化数据。
练习题示例与解析: 22.题目:给定一个包含学生成绩的字典列表,计算每个学生的平均分,并按平均分从高到低排序。 ```python students = [ {"name": "Alice", "grades": [85, 90, 78]}, {"name": "Bob", "grades": [92, 88, 95]}, {"name": "Charlie", "grades": [70, 75, 80]}, {"name": "Diana", "grades": [88, 92, 85, 90]}, ]
# 计算平均分并添加到字典中 for student in students: grades = student["grades"] student["average"] = sum(grades) / len(grades) # 按平均分降序排序 # sorted() 函数配合 lambda 表达式 students_sorted = sorted(students, key=lambda x: x["average"], reverse=True) # 格式化输出 print("学生成绩排名:") print("-" * 30) for i, student in enumerate(students_sorted, start=1): print(f"{i}. {student['name']:10} 平均分: {student['average']:.2f} 各科成绩: {student['grades']}") ``` **关键点**: - `sorted(iterable, key=..., reverse=...)`是强大的排序工具。 - `lambda`匿名函数常用于定义简单的、一次性的函数逻辑。 - 字符串格式化(如`{student['name']:10}`)用于对齐输出。- 题目:从一段日志文本中,提取所有符合特定格式的日期(如YYYY-MM-DD)。
关键点:正则表达式import re # 导入正则表达式模块 log_text = """ 用户登录日志: 2023-10-01 09:15:22 用户A登录成功。 错误发生在2023-10-02 14:30:11。 2023/10/03 这是一个错误格式的日期。 系统备份于 2023-10-05 凌晨。 最后更新:2023-11-15。 """ # 定义正则表达式模式:YYYY-MM-DD date_pattern = r'\d{4}-\d{2}-\d{2}' # 使用 findall 查找所有匹配项 dates_found = re.findall(date_pattern, log_text) print("从日志中提取的日期:") for date in dates_found: print(f" - {date}") # 更精确的模式,考虑月份和日期的有效性(简单版) better_pattern = r'\b(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])\b' better_dates = re.findall(better_pattern, log_text) print("\n使用更精确模式提取的日期:") for date in better_dates: print(f" - {date}")re模块是处理复杂文本匹配和提取的利器。编写模式时需仔细测试其准确性和全面性。
6.2 小型项目实战
目标:综合运用多个知识点,完成一个完整的小功能。
练习题示例与解析: 24.题目:实现一个简单的通讯录管理系统,支持添加、删除、查找、显示所有联系人(信息包括姓名和电话)。 ```python class ContactManager: """简易通讯录管理器"""
def __init__(self): self.contacts = {} # 用字典存储,姓名作为键,电话作为值 def add_contact(self, name, phone): """添加联系人""" if name in self.contacts: print(f"联系人 '{name}' 已存在,电话为: {self.contacts[name]}") overwrite = input("是否覆盖?(y/n): ").lower() if overwrite != 'y': print("已取消添加。") return self.contacts[name] = phone print(f"联系人 '{name}' 添加/更新成功。") def delete_contact(self, name): """删除联系人""" if name in self.contacts: del self.contacts[name] print(f"联系人 '{name}' 已删除。") else: print(f"未找到联系人 '{name}'。") def find_contact(self, name): """查找联系人""" phone = self.contacts.get(name) if phone: print(f"找到联系人: {name} - 电话: {phone}") else: print(f"未找到联系人 '{name}'。") def show_all_contacts(self): """显示所有联系人""" if not self.contacts: print("通讯录为空。") return print("\n=== 所有联系人 ===") for name, phone in sorted(self.contacts.items()): # 按姓名排序显示 print(f" {name:10} : {phone}") print("===================\n") def run(self): """运行通讯录管理程序""" while True: print("\n--- 通讯录管理系统 ---") print("1. 添加联系人") print("2. 删除联系人") print("3. 查找联系人") print("4. 显示所有联系人") print("5. 退出") choice = input("请选择操作 (1-5): ").strip() if choice == '1': name = input("请输入姓名: ").strip() phone = input("请输入电话: ").strip() if name and phone: self.add_contact(name, phone) else: print("姓名和电话不能为空!") elif choice == '2': name = input("请输入要删除的姓名: ").strip() self.delete_contact(name) elif choice == '3': name = input("请输入要查找的姓名: ").strip() self.find_contact(name) elif choice == '4': self.show_all_contacts() elif choice == '5': print("感谢使用,再见!") break else: print("无效选择,请重新输入。") # 启动程序 if __name__ == "__main__": manager = ContactManager() manager.run() ``` **关键点**: - 使用类来组织数据和逻辑,使代码结构清晰。 - 字典是存储键值对数据的理想选择。 - `if __name__ == "__main__":` 确保当该文件作为主程序运行时才执行启动代码,这在模块化开发中很重要。 - 提供了简单的命令行交互界面。7. 常见问题与高效练习策略
在练习过程中,你一定会遇到各种问题。本节汇总了高频问题及其解决方案,并给出持续提升的建议。
7.1 练习中常见错误与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
SyntaxError: invalid syntax | 语法错误,如括号不匹配、冒号缺失、缩进错误、使用了中文标点。 | 仔细检查错误提示行附近的代码结构。使用IDE的语法高亮和自动缩进功能。 |
NameError: name ‘xxx’ is not defined | 变量或函数名在使用前未定义,或拼写错误。 | 检查变量名是否拼写正确,确认其定义在使用之前。注意变量作用域。 |
IndentationError: unexpected indent | 缩进不一致(混用空格和Tab)。 | 在编辑器中设置“将制表符转换为空格”(通常为4个空格)。统一缩进风格。 |
TypeError: can only concatenate str (not “int”) to str | 字符串与数字等不同类型数据直接拼接。 | 使用str()函数将非字符串转换为字符串,或使用f-string、format()方法。 |
IndexError: list index out of range | 列表索引超出了有效范围(如对空列表使用list[0])。 | 在访问索引前,检查列表长度len(list)。考虑使用try-except捕获异常。 |
KeyError: ‘some_key’ | 访问字典中不存在的键。 | 使用dict.get(‘key’, default_value)方法安全访问,或先用‘key’ in dict判断。 |
ZeroDivisionError: division by zero | 除数为零。 | 在进行除法运算前,判断除数是否为零。 |
| 程序逻辑正确,但结果不对 | 算法逻辑有误、边界条件未考虑、变量值被意外修改。 | 使用print()输出中间变量值进行调试。或使用IDE的调试器设置断点,单步执行。 |
7.2 如何从“会做题”到“会编程”
完成基础练习后,如何进一步提升?
- 阅读优秀代码:在GitHub上寻找与你练习题目相关的开源项目,学习别人的代码风格、架构设计和问题解决思路。
- 参与实际项目:尝试用Python自动化你的日常工作(如处理Excel报表、整理文件、爬取公开数据),或参与一些小型的开源项目。
- 学习数据结构与算法:这是编程的内功。可以系统学习链表、栈、队列、树、图等基础数据结构,以及排序、查找等经典算法。LeetCode、牛客网是很好的练习平台。
- 深入特定领域:Python应用广泛,确定一个你感兴趣的方向深入,如:
- Web开发:学习Django或Flask框架。
- 数据分析:掌握Pandas, NumPy, Matplotlib。
- 机器学习/AI:学习Scikit-learn, TensorFlow, PyTorch。
- 自动化运维/测试:学习Ansible, Selenium, pytest。
- 养成良好习惯:
- 写注释和文档:为你写的函数、类添加
docstring,解释其作用和参数。 - 代码风格:遵循PEP 8规范,使用工具(如
black,autopep8)格式化代码。 - 版本控制:学习使用Git管理你的代码,这是团队协作的基石。
- 单元测试:为你重要的函数编写测试用例,确保代码的可靠性。
- 写注释和文档:为你写的函数、类添加
编程能力的提升没有捷径,它源于对每一个细节的深思熟虑和成千上万行代码的锤炼。这330道练习题是一个系统化的起点,旨在帮你构建坚实的Python基础思维和编码手感。坚持每天解决几个问题,主动思考更优解,并尝试将代码应用到实际场景中,你一定会发现自己的编程能力在不知不觉中变得“老腻害了”。记住,编程是一门实践的艺术,动手去写,去调试,去优化,是通往“大神”之路的唯一法门。