引言:为什么实战练习是编程学习的核心
编程是一门实践性极强的技能,仅仅阅读理论书籍或观看视频教程是远远不够的。从零基础到能够独立完成项目实战,需要通过大量的代码练习来巩固基础知识、培养逻辑思维和解决问题的能力。本指南将为你精选一系列从基础到进阶的经典编程练习题,每个题目都配有详细的解析和完整的代码示例,帮助你逐步建立编程自信,最终达到项目实战的水平。
无论你是完全的编程新手,还是有一定基础想要提升实战能力的学习者,这些练习题都能为你提供系统化的训练路径。我们将按照难度递进的顺序,从最基本的语法练习到完整的项目实战,每个阶段都有明确的学习目标和实践任务。
第一阶段:基础语法与逻辑思维训练(1-2周)
1.1 数字运算与条件判断
题目1:判断素数(Prime Number Checker)
题目描述:编写一个程序,接收用户输入的一个正整数,判断该数字是否为素数(质数),并输出相应的提示信息。
学习目标:
- 掌握基本的输入输出操作
- 理解循环结构和条件判断
- 学习使用标志变量(flag)控制程序流程
详细解析: 素数是指大于1的自然数,除了1和它本身以外不再有其他因数的数。判断素数的核心思路是:尝试用从2到该数平方根的所有整数去除它,如果都不能整除,则该数为素数。
完整代码示例:
import math
def is_prime(n):
"""
判断一个数是否为素数
:param n: 待判断的整数
:return: True如果是素数,False如果不是
"""
# 处理小于2的特殊情况
if n < 2:
return False
# 处理2这个特殊情况(2是唯一的偶素数)
if n == 2:
return True
# 处理偶数(除了2以外的偶数都不是素数)
if n % 2 == 0:
return False
# 只需要检查到平方根即可,因为如果n有大于平方根的因数,
# 那么必然有小于平方根的对应因数
sqrt_n = int(math.sqrt(n)) + 1
# 从3开始,每次加2(跳过偶数),检查到平方根为止
for i in range(3, sqrt_n, 2):
if n % i == 0:
return False
return True
# 主程序
def main():
print("=== 素数判断器 ===")
while True:
try:
num_str = input("请输入一个正整数(输入q退出):")
if num_str.lower() == 'q':
print("程序已退出,谢谢使用!")
break
num = int(num_str)
if num < 1:
print("请输入大于0的正整数!")
continue
if is_prime(num):
print(f"✅ {num} 是素数!")
else:
print(f"❌ {num} 不是素数!")
except ValueError:
print("输入无效,请输入数字!")
except Exception as e:
print(f"发生错误:{e}")
if __name__ == "__main__":
main()
代码逐行解析:
import math:导入数学模块,用于计算平方根def is_prime(n)::定义判断素数的函数if n < 2::处理边界情况,小于2的数不是素数if n == 2::2是唯一的偶素数,需要单独处理if n % 2 == 0::快速排除所有偶数sqrt_n = int(math.sqrt(n)) + 1:计算平方根,优化循环次数for i in range(3, sqrt_n, 2):从3开始,每次加2,跳过偶数if n % i == 0::如果能被整除,说明不是素数while True和try-except:构建健壮的用户交互循环
运行示例:
=== 素数判断器 ===
请输入一个正整数(输入q退出):17
✅ 17 是素数!
请输入一个正整数(输入q退出):100
❌ 100 不是素数!
请输入一个正整数(输入q退出):2
✅ 2 是素数!
请输入一个正整数(输入q退出):q
程序已退出,谢谢使用!
题目2:斐波那契数列生成器
题目描述:编写一个程序,生成斐波那契数列的前N项。斐波那契数列的定义是:前两项是0和1,从第三项开始,每一项都等于前两项之和。
学习目标:
- 掌握列表操作和循环结构
- 理解递归与迭代的区别
- 学习函数参数传递和返回值
完整代码示例:
def fibonacci_iterative(n):
"""
迭代方式生成斐波那契数列
:param n: 要生成的项数
:return: 包含n项斐波那契数列的列表
"""
if n <= 0:
return []
elif n == 1:
return [0]
elif n == 2:
return [0, 1]
# 初始化前两项
fib_list = [0, 1]
# 从第3项开始计算
for i in range(2, n):
# 新项 = 前两项之和
next_fib = fib_list[i-1] + fib_list[i-2]
fib_list.append(next_fib)
return fib_list
def fibonacci_recursive(n, a=0, b=1):
"""
递归方式生成斐波那契数列(仅用于演示,效率较低)
"""
if n <= 0:
return []
if n == 1:
return [a]
return [a] + fibonacci_recursive(n-1, b, a+b)
def fibonacci_generator(n):
"""
使用生成器的方式(内存效率最高)
"""
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
def main():
print("=== 斐波那契数列生成器 ===")
while True:
try:
num_str = input("请输入要生成的项数(输入q退出):")
if num_str.lower() == 'q':
break
n = int(num_str)
if n < 1:
print("请输入正整数!")
continue
print(f"\n迭代方式结果:")
result1 = fibonacci_iterative(n)
print(result1)
print(f"\n生成器方式结果:")
result2 = list(fibonacci_generator(n))
print(result2)
# 性能对比(当n很大时,递归方式会很慢)
if n <= 20:
print(f"\n递归方式结果:")
result3 = fibonacci_recursive(n)
print(result3)
print("-" * 40)
except ValueError:
print("请输入有效的数字!")
except Exception as e:
print(f"错误:{e}")
if __name__ == "__main__":
main()
代码深度解析:
- 迭代方式:最常用且效率最高的方法,使用列表存储结果,时间复杂度O(n)
- 递归方式:代码简洁但效率低,有重复计算问题,时间复杂度O(2^n),仅用于学习
- 生成器方式:使用
yield关键字,内存占用最小,适合处理大数据量
复杂度分析:
- 时间复杂度:迭代和生成器都是O(n),递归是O(2^n)
- 空间复杂度:迭代O(n),生成器O(1),递归O(n)(调用栈)
1.2 字符串处理与数据结构
题目3:回文字符串检测器
题目描述:编写一个程序,判断用户输入的字符串是否为回文(正读和反读都相同,忽略大小写、空格和标点符号)。
学习目标:
- 字符串清洗和预处理
- 字符串切片操作
- 正则表达式基础应用
完整代码示例:
import re
def is_palindrome_simple(text):
"""
简单方式:使用字符串切片
"""
# 移除空格和标点,转为小写
cleaned = ''.join(char.lower() for char in text if char.isalnum())
return cleaned == cleaned[::-1]
def is_palindrome_two_pointers(text):
"""
双指针方式:更高效的算法
"""
cleaned = ''.join(char.lower() for char in text if char.isalnum())
left, right = 0, len(cleaned) - 1
while left < right:
if cleaned[left] != cleaned[right]:
return False
left += 1
right -= 1
return True
def is_palindrome_regex(text):
"""
使用正则表达式清洗字符串
"""
# 移除所有非字母数字字符
cleaned = re.sub(r'[^a-zA-Z0-9]', '', text).lower()
return cleaned == cleaned[::-1]
def main():
print("=== 回文检测器 ===")
test_cases = [
"A man, a plan, a canal: Panama",
"race a car",
"Was it a car or a cat I saw?",
"No 'x' in Nixon",
"hello world",
"上海自来水来自海上"
]
print("测试用例演示:")
for test in test_cases:
result1 = is_palindrome_simple(test)
result2 = is_palindrome_two_pointers(test)
result3 = is_palindrome_regex(test)
print(f"\n输入:'{test}'")
print(f" 简单方式:{result1}")
print(f" 双指针方式:{result2}")
print(f" 正则方式:{result3}")
# 用户交互模式
print("\n" + "="*40)
print("用户输入模式:")
while True:
user_input = input("\n请输入要检测的字符串(输入q退出):")
if user_input.lower() == 'q':
break
result = is_palindrome_simple(user_input)
if result:
print(f"✅ '{user_input}' 是回文!")
else:
print(f"❌ '{user_input}' 不是回文!")
if __name__ == "__main__":
main()
代码要点解析:
char.isalnum():判断字符是否为字母或数字cleaned[::-1]:Python字符串切片,-1表示反转- 双指针算法:left和right指针向中间移动,效率更高
- 正则表达式:
re.sub(r'[^a-zA-Z0-9]', '', text)移除所有非字母数字字符
运行示例:
=== 回文检测器 ===
测试用例演示:
输入:'A man, a plan, a canal: Panama'
简单方式:True
双指针方式:True
正则方式:True
输入:'race a car'
简单方式:False
双指针方式:False
正则方式:False
第二阶段:数据结构与算法基础(2-3周)
2.1 数组与列表操作
题目4:数组中第K个最大元素
题目描述:给定一个整数数组,找到第K个最大元素。你可以假设K总是有效的,且1 ≤ K ≤ 数组长度。
学习目标:
- 掌握排序算法
- 理解优先队列/堆数据结构
- 学习快速选择算法
完整代码示例:
import heapq
import random
def find_kth_largest_sort(nums, k):
"""
方法1:排序后取第K个
时间复杂度:O(n log n)
空间复杂度:O(1)
"""
nums.sort()
return nums[-k]
def find_kth_largest_heap(nums, k):
"""
方法2:使用最小堆
时间复杂度:O(n log k)
空间复杂度:O(k)
"""
# 创建大小为k的最小堆
min_heap = []
for num in nums:
if len(min_heap) < k:
heapq.heappush(min_heap, num)
else:
# 如果当前数比堆顶大,替换堆顶
if num > min_heap[0]:
heapq.heapreplace(min_heap, num)
return min_heap[0]
def find_kth_largest_quickselect(nums, k):
"""
方法3:快速选择算法(最优解)
平均时间复杂度:O(n)
最坏时间复杂度:O(n²)
空间复杂度:O(1)
"""
def quickselect(left, right, k_smallest):
if left == right:
return nums[left]
# 随机选择pivot,避免最坏情况
pivot_index = random.randint(left, right)
pivot_index = partition(left, right, pivot_index)
if k_smallest == pivot_index:
return nums[k_smallest]
elif k_smallest < pivot_index:
return quickselect(left, pivot_index - 1, k_smallest)
else:
return quickselect(pivot_index + 1, right, k_smallest)
def partition(left, right, pivot_index):
pivot_value = nums[pivot_index]
# 将pivot移到末尾
nums[pivot_index], nums[right] = nums[right], nums[pivot_index]
store_index = left
for i in range(left, right):
if nums[i] < pivot_value:
nums[store_index], nums[i] = nums[i], nums[store_index]
store_index += 1
# 将pivot放到正确位置
nums[right], nums[store_index] = nums[store_index], nums[right]
return store_index
# 转换为寻找第(n-k+1)小的元素
return quickselect(0, len(nums) - 1, len(nums) - k)
def main():
print("=== 查找数组中第K个最大元素 ===")
# 测试数据
nums = [3, 2, 1, 5, 6, 4]
k = 2
print(f"数组:{nums}")
print(f"K值:{k}")
print(f"期望结果:5")
print("\n三种方法对比:")
result1 = find_kth_largest_sort(nums.copy(), k)
print(f"排序方法:{result1}")
result2 = find_kth_largest_heap(nums.copy(), k)
print(f"堆方法:{result2}")
result3 = find_kth_largest_quickselect(nums.copy(), k)
print(f"快速选择:{result3}")
# 性能测试(大数据量)
print("\n性能测试(100万数据,找第1000大):")
large_nums = [random.randint(1, 1000000) for _ in range(1000000)]
import time
# 只测试堆和快速选择,排序太慢
start = time.time()
result_heap = find_kth_largest_heap(large_nums.copy(), 1000)
time_heap = time.time() - start
start = time.time()
result_quick = find_kth_largest_quickselect(large_nums.copy(), 1000)
time_quick = time.time() - start
print(f"堆方法耗时:{time_heap:.4f}秒,结果:{result_heap}")
print(f"快速选择耗时:{time_quick:.4f}秒,结果:{result_quick}")
if __name__ == "__main__":
main()
算法深度解析:
- 排序方法:最简单直接,但效率最低,适合小数据量
- 堆方法:维护一个大小为k的最小堆,堆顶就是第k大元素
- 快速选择:基于快速排序的partition思想,平均O(n),是最优解
关键点:
heapq模块提供了最小堆实现- 快速选择的核心是partition操作
- 随机化pivot避免最坏情况O(n²)
2.2 哈希表与映射
题目5:两数之和(Two Sum)
题目描述:给定一个整数数组和一个目标值,找出数组中和为目标值的两个数的索引。假设每个输入只对应唯一的答案。
学习目标:
- 哈希表的使用
- 字典的键值对操作
- 空间换时间的权衡
完整代码示例:
def two_sum_brute_force(nums, target):
"""
暴力解法:双重循环
时间复杂度:O(n²)
空间复杂度:O(1)
"""
n = len(nums)
for i in range(n):
for j in range(i + 1, n):
if nums[i] + nums[j] == target:
return [i, j]
return []
def two_sum_hash_table(nums, target):
"""
哈希表解法:一次遍历
时间复杂度:O(n)
空间复杂度:O(n)
"""
hash_map = {} # 存储值到索引的映射
for i, num in enumerate(nums):
complement = target - num
# 检查补数是否在哈希表中
if complement in hash_map:
return [hash_map[complement], i]
# 将当前数存入哈希表
hash_map[num] = i
return []
def two_sum_sorted(nums, target):
"""
双指针解法(需要先排序)
时间复杂度:O(n log n)
空间复杂度:O(1)
"""
# 创建索引-值对列表并排序
indexed_nums = [(val, idx) for idx, val in enumerate(nums)]
indexed_nums.sort()
left, right = 0, len(indexed_nums) - 1
while left < right:
current_sum = indexed_nums[left][0] + indexed_nums[right][0]
if current_sum == target:
return [indexed_nums[left][1], indexed_nums[right][1]]
elif current_sum < target:
left += 1
else:
right -= 1
return []
def main():
print("=== 两数之和问题 ===")
# 测试用例
test_cases = [
([2, 7, 11, 15], 9),
([3, 2, 4], 6),
([3, 3], 6),
([1, 2, 3, 4, 5], 10)
]
for nums, target in test_cases:
print(f"\n数组:{nums},目标:{target}")
result1 = two_sum_brute_force(nums, target)
result2 = two_sum_hash_table(nums, target)
result3 = two_sum_sorted(nums, target)
print(f"暴力解法:{result1}")
print(f"哈希表解法:{result2}")
print(f"双指针解法:{result3}")
# 性能对比
print("\n" + "="*50)
print("性能对比测试:")
# 生成大规模测试数据
import random, time
large_nums = [random.randint(1, 10000) for _ in range(10000)]
target = 15000
# 暴力解法(只测试小规模)
small_nums = large_nums[:100]
start = time.time()
two_sum_brute_force(small_nums, target)
time_brute = time.time() - start
# 哈希表解法
start = time.time()
two_sum_hash_table(large_nums, target)
time_hash = time.time() - start
# 双指针解法
start = time.time()
two_sum_sorted(large_nums, target)
time_sorted = time.time() - start
print(f"暴力解法(100个元素):{time_brute:.6f}秒")
print(f"哈希表解法(10000个元素):{time_hash:.6f}秒")
print(f"双指针解法(10000个元素):{time_sorted:.6f}秒")
if __name__ == "__main__":
main()
代码要点解析:
enumerate():同时获取索引和值in操作符:检查键是否在字典中,O(1)时间复杂度- 哈希表的核心思想:用空间换时间,将查找时间从O(n)降到O(1)
运行示例:
=== 两数之和问题 ===
数组:[2, 7, 11, 15],目标:9
暴力解法:[0, 1]
哈希表解法:[0, 1]
双指针解法:[0, 1]
数组:[3, 2, 4],目标:6
暴力解法:[1, 2]
哈希表解法:[1, 2]
双指针解法:[1, 2]
第三阶段:面向对象编程与文件操作(2-3周)
3.1 类与对象基础
题目6:学生信息管理系统
题目描述:设计一个学生信息管理系统,包含学生类(Student)和管理类(StudentManager),支持添加、删除、查询、修改和统计功能。
学习目标:
- 类的定义和实例化
- 封装、继承、多态
- 异常处理
- 文件持久化存储
完整代码示例:
import json
import os
from datetime import datetime
class Student:
"""学生类,封装学生信息"""
def __init__(self, student_id, name, age, score):
self.student_id = student_id
self.name = name
self.age = age
self.score = score
def __str__(self):
"""字符串表示"""
return f"学号:{self.student_id},姓名:{self.name},年龄:{self.age},成绩:{self.score}"
def __repr__(self):
"""官方表示,用于调试"""
return f"Student({self.student_id}, '{self.name}', {self.age}, {self.score})"
def get_grade(self):
"""根据成绩获取等级"""
if self.score >= 90:
return "A"
elif self.score >= 80:
return "B"
elif self.score >= 70:
return "C"
elif self.score >= 60:
return "D"
else:
return "E"
def is_pass(self):
"""判断是否及格"""
return self.score >= 60
def to_dict(self):
"""转换为字典,用于JSON序列化"""
return {
"student_id": self.student_id,
"name": self.name,
"age": self.age,
"score": self.score
}
class StudentManager:
"""学生管理类,提供增删改查功能"""
def __init__(self, data_file="students.json"):
self.data_file = data_file
self.students = {} # 使用字典存储,key为学号
self.load_data()
def add_student(self, student):
"""添加学生"""
if student.student_id in self.students:
raise ValueError(f"学号 {student.student_id} 已存在!")
self.students[student.student_id] = student
print(f"✅ 学生 {student.name} 添加成功!")
def delete_student(self, student_id):
"""删除学生"""
if student_id not in self.students:
raise ValueError(f"学号 {student_id} 不存在!")
student = self.students.pop(student_id)
print(f"✅ 学生 {student.name} 已删除!")
def find_student(self, student_id):
"""查找学生"""
return self.students.get(student_id)
def update_student(self, student_id, **kwargs):
"""更新学生信息"""
if student_id not in self.students:
raise ValueError(f"学号 {student_id} 不存在!")
student = self.students[student_id]
for key, value in kwargs.items():
if hasattr(student, key):
setattr(student, key, value)
print(f"✅ 学生 {student.name} 信息已更新!")
def get_all_students(self):
"""获取所有学生"""
return list(self.students.values())
def get_pass_rate(self):
"""计算及格率"""
total = len(self.students)
if total == 0:
return 0
passed = sum(1 for s in self.students.values() if s.is_pass())
return passed / total
def get_average_score(self):
"""计算平均分"""
if not self.students:
return 0
total = sum(s.score for s in self.students.values())
return total / len(self.students)
def save_data(self):
"""保存数据到文件"""
data = {
"students": [s.to_dict() for s in self.students.values()],
"last_updated": datetime.now().isoformat()
}
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"💾 数据已保存到 {self.data_file}")
def load_data(self):
"""从文件加载数据"""
if not os.path.exists(self.data_file):
return
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
for student_data in data.get("students", []):
student = Student(**student_data)
self.students[student.student_id] = student
print(f"📂 已加载 {len(self.students)} 条学生记录")
except Exception as e:
print(f"加载数据失败:{e}")
def display_menu():
"""显示菜单"""
print("\n" + "="*40)
print(" 学生信息管理系统")
print("="*40)
print("1. 添加学生")
print("2. 删除学生")
print("3. 查找学生")
print("4. 修改学生信息")
print("5. 显示所有学生")
print("6. 统计信息")
print("7. 保存数据")
print("0. 退出系统")
print("="*40)
def main():
manager = StudentManager()
while True:
display_menu()
choice = input("请选择操作(0-7):")
try:
if choice == "0":
print("感谢使用,再见!")
break
elif choice == "1":
student_id = input("学号:")
name = input("姓名:")
age = int(input("年龄:"))
score = float(input("成绩:"))
student = Student(student_id, name, age, score)
manager.add_student(student)
elif choice == "2":
student_id = input("请输入要删除的学号:")
manager.delete_student(student_id)
elif choice == "3":
student_id = input("请输入要查找的学号:")
student = manager.find_student(student_id)
if student:
print(student)
else:
print("未找到该学生!")
elif choice == "4":
student_id = input("请输入要修改的学号:")
if manager.find_student(student_id):
print("请输入要修改的信息(直接回车保持原值):")
name = input("新姓名:")
age = input("新年龄:")
score = input("新成绩:")
updates = {}
if name: updates['name'] = name
if age: updates['age'] = int(age)
if score: updates['score'] = float(score)
manager.update_student(student_id, **updates)
elif choice == "5":
students = manager.get_all_students()
if not students:
print("暂无学生记录!")
else:
print("\n所有学生信息:")
for s in students:
print(s)
elif choice == "6":
print("\n统计信息:")
print(f"学生总数:{len(manager.students)}")
print(f"平均分:{manager.get_average_score():.2f}")
print(f"及格率:{manager.get_pass_rate()*100:.1f}%")
elif choice == "7":
manager.save_data()
else:
print("无效选择,请重新输入!")
except Exception as e:
print(f"操作出错:{e}")
input("\n按回车键继续...")
if __name__ == "__main__":
main()
代码深度解析:
- 封装:Student类将数据和操作封装在一起
- 异常处理:使用raise ValueError处理业务逻辑错误
- 文件操作:使用JSON格式存储数据,便于读写
- 动态参数:
**kwargs实现灵活的更新操作 - 数据持久化:程序关闭后数据不丢失
运行示例:
📂 已加载 0 条学生记录
========================================
学生信息管理系统
========================================
1. 添加学生
2. 删除学生
3. 查找学生
4. 修改学生信息
5. 显示所有学生
6. 统计信息
7. 保存数据
0. 退出系统
========================================
请选择操作(0-7):1
学号:2021001
姓名:张三
年龄:20
成绩:85
✅ 学生 张三 添加成功!
第四阶段:项目实战(3-4周)
4.1 项目1:简易通讯录管理系统
项目描述:实现一个功能完整的命令行通讯录系统,支持联系人管理、分组、搜索、导入导出等功能。
项目架构设计:
- 数据层:JSON文件存储
- 业务层:Contact类、AddressBook类
- 表现层:命令行交互界面
完整代码实现:
import json
import csv
import os
from datetime import datetime
from typing import List, Optional
class Contact:
"""联系人类"""
def __init__(self, name: str, phone: str, email: str = "", group: str = "默认"):
self.name = name
self.phone = phone
self.email = email
self.group = group
self.created_at = datetime.now().isoformat()
def __str__(self):
return f"【{self.group}】{self.name} - {self.phone} ({self.email})"
def to_dict(self):
return {
"name": self.name,
"phone": self.phone,
"email": self.email,
"group": self.group,
"created_at": self.created_at
}
@classmethod
def from_dict(cls, data):
contact = cls(data["name"], data["phone"], data.get("email", ""), data.get("group", "默认"))
contact.created_at = data.get("created_at", datetime.now().isoformat())
return contact
class AddressBook:
"""通讯录管理类"""
def __init__(self, data_file="contacts.json"):
self.data_file = data_file
self.contacts: List[Contact] = []
self.load_data()
def add_contact(self, contact: Contact):
"""添加联系人"""
# 检查是否已存在
for c in self.contacts:
if c.phone == contact.phone:
raise ValueError(f"电话号码 {contact.phone} 已存在!")
self.contacts.append(contact)
print(f"✅ 添加联系人:{contact.name}")
def delete_contact(self, phone: str):
"""删除联系人"""
for i, c in enumerate(self.contacts):
if c.phone == phone:
del self.contacts[i]
print(f"✅ 删除联系人:{c.name}")
return
raise ValueError(f"未找到电话号码:{phone}")
def search_contacts(self, keyword: str, search_by: str = "name") -> List[Contact]:
"""搜索联系人"""
results = []
keyword = keyword.lower()
for contact in self.contacts:
if search_by == "name" and keyword in contact.name.lower():
results.append(contact)
elif search_by == "phone" and keyword in contact.phone:
results.append(contact)
elif search_by == "group" and keyword in contact.group.lower():
results.append(contact)
return results
def update_contact(self, phone: str, **kwargs):
"""更新联系人"""
for contact in self.contacts:
if contact.phone == phone:
for key, value in kwargs.items():
if hasattr(contact, key):
setattr(contact, key, value)
print(f"✅ 更新联系人:{contact.name}")
return
raise ValueError(f"未找到电话号码:{phone}")
def get_all_groups(self):
"""获取所有分组"""
groups = {}
for contact in self.contacts:
groups[contact.group] = groups.get(contact.group, 0) + 1
return groups
def export_to_csv(self, filename: str):
"""导出到CSV"""
if not self.contacts:
print("没有联系人可导出!")
return
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(["姓名", "电话", "邮箱", "分组", "创建时间"])
for c in self.contacts:
writer.writerow([c.name, c.phone, c.email, c.group, c.created_at])
print(f"✅ 已导出到 {filename}")
def import_from_csv(self, filename: str):
"""从CSV导入"""
if not os.path.exists(filename):
raise FileNotFoundError(f"文件 {filename} 不存在!")
count = 0
with open(filename, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
contact = Contact(
name=row["姓名"],
phone=row["电话"],
email=row.get("邮箱", ""),
group=row.get("分组", "默认")
)
self.add_contact(contact)
count += 1
except Exception as e:
print(f"跳过错误行:{e}")
print(f"✅ 成功导入 {count} 个联系人")
def save_data(self):
"""保存数据"""
data = {
"contacts": [c.to_dict() for c in self.contacts],
"last_updated": datetime.now().isoformat()
}
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"💾 数据已保存")
def load_data(self):
"""加载数据"""
if not os.path.exists(self.data_file):
return
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.contacts = [Contact.from_dict(c) for c in data.get("contacts", [])]
print(f"📂 已加载 {len(self.contacts)} 个联系人")
except Exception as e:
print(f"加载数据失败:{e}")
def main():
book = AddressBook()
while True:
print("\n" + "="*50)
print("通讯录管理系统".center(48))
print("="*50)
print("1. 添加联系人")
print("2. 删除联系人")
print("3. 搜索联系人")
print("4. 修改联系人")
print("5. 显示所有联系人")
print("6. 分组统计")
print("7. 导出CSV")
print("8. 导入CSV")
print("9. 保存数据")
print("0. 退出系统")
print("="*50)
choice = input("请选择:").strip()
try:
if choice == "0":
save = input("退出前是否保存数据?(y/n): ")
if save.lower() == "y":
book.save_data()
print("再见!")
break
elif choice == "1":
name = input("姓名:")
phone = input("电话:")
email = input("邮箱(可选):")
group = input("分组(默认):") or "默认"
contact = Contact(name, phone, email, group)
book.add_contact(contact)
elif choice == "2":
phone = input("请输入要删除的电话:")
book.delete_contact(phone)
elif choice == "3":
keyword = input("搜索关键词:")
by = input("搜索方式(name/phone/group,默认name):") or "name"
results = book.search_contacts(keyword, by)
if results:
print(f"\n找到 {len(results)} 个结果:")
for c in results:
print(c)
else:
print("未找到匹配的联系人!")
elif choice == "4":
phone = input("请输入要修改的电话:")
print("输入新信息(直接回车保持原值):")
name = input("新姓名:")
email = input("新邮箱:")
group = input("新分组:")
updates = {}
if name: updates['name'] = name
if email: updates['email'] = email
if group: updates['group'] = group
book.update_contact(phone, **updates)
elif choice == "5":
if not book.contacts:
print("暂无联系人!")
else:
print(f"\n共 {len(book.contacts)} 个联系人:")
for c in book.contacts:
print(c)
elif choice == "6":
groups = book.get_all_groups()
print("\n分组统计:")
for group, count in groups.items():
print(f" {group}: {count} 人")
elif choice == "7":
filename = input("导出文件名(默认contacts.csv):") or "contacts.csv"
book.export_to_csv(filename)
elif choice == "8":
filename = input("导入文件名:")
book.import_from_csv(filename)
elif choice == "9":
book.save_data()
else:
print("无效选择!")
except Exception as e:
print(f"错误:{e}")
input("\n按回车键继续...")
if __name__ == "__main__":
main()
项目特点:
- 模块化设计:Contact和AddressBook类职责清晰
- 数据持久化:支持JSON和CSV两种格式
- 错误处理:完善的异常处理机制
- 用户友好:清晰的菜单和提示信息
- 扩展性:易于添加新功能(如分组管理、备份等)
4.2 项目2:简易计算器(GUI版本)
项目描述:使用Tkinter创建图形界面计算器,支持基本运算、历史记录和科学计算功能。
完整代码实现:
import tkinter as tk
from tkinter import messagebox
import math
class Calculator:
"""图形界面计算器"""
def __init__(self, root):
self.root = root
self.root.title("简易计算器")
self.root.geometry("400x550")
self.root.resizable(False, False)
# 表达式和结果
self.expression = ""
self.result_var = tk.StringVar()
self.result_var.set("0")
# 历史记录
self.history = []
self.create_widgets()
def create_widgets(self):
"""创建界面组件"""
# 显示区域
display_frame = tk.Frame(self.root, bg="#f0f0f0", padx=10, pady=10)
display_frame.pack(fill="x")
# 历史记录标签
self.history_label = tk.Label(
display_frame,
text="历史记录:",
font=("Arial", 10),
bg="#f0f0f0",
fg="#666",
anchor="w"
)
self.history_label.pack(fill="x")
# 结果显示
result_label = tk.Label(
display_frame,
textvariable=self.result_var,
font=("Arial", 24, "bold"),
bg="#f0f0f0",
fg="#000",
anchor="e",
padx=5
)
result_label.pack(fill="x", pady=5)
# 按钮区域
button_frame = tk.Frame(self.root, bg="#ddd")
button_frame.pack(fill="both", expand=True, padx=5, pady=5)
# 按钮布局
buttons = [
["C", "⌫", "%", "/"],
["7", "8", "9", "*"],
["4", "5", "6", "-"],
["1", "2", "3", "+"],
["0", ".", "=", "√"]
]
for i, row in enumerate(buttons):
for j, text in enumerate(row):
btn = tk.Button(
button_frame,
text=text,
font=("Arial", 14),
width=5,
height=2,
bg=self.get_button_color(text),
fg="#000" if text not in ["C", "⌫"] else "#d00",
command=lambda t=text: self.on_button_click(t)
)
btn.grid(row=i, column=j, padx=2, pady=2, sticky="nsew")
# 配置网格权重
for i in range(5):
button_frame.grid_rowconfigure(i, weight=1)
for j in range(4):
button_frame.grid_columnconfigure(j, weight=1)
# 历史记录按钮
history_btn = tk.Button(
self.root,
text="查看历史记录",
font=("Arial", 10),
bg="#4CAF50",
fg="white",
command=self.show_history
)
history_btn.pack(fill="x", padx=10, pady=5)
def get_button_color(self, text):
"""根据按钮文本返回颜色"""
if text in ["C", "⌫"]:
return "#ffcccc"
elif text in ["+", "-", "*", "/", "=", "%", "√"]:
return "#ffaa00"
else:
return "#e0e0e0"
def on_button_click(self, text):
"""按钮点击事件处理"""
if text == "C":
self.expression = ""
self.result_var.set("0")
elif text == "⌫":
self.expression = self.expression[:-1]
if not self.expression:
self.result_var.set("0")
else:
self.result_var.set(self.expression)
elif text == "=":
self.calculate()
elif text == "√":
self.square_root()
elif text == "%":
self.expression += "%"
self.result_var.set(self.expression)
else:
# 数字和运算符
self.expression += text
self.result_var.set(self.expression)
def calculate(self):
"""计算表达式"""
if not self.expression:
return
try:
# 处理百分号
expr = self.expression.replace("%", "/100")
# 安全计算(使用eval,实际项目中应避免)
result = eval(expr)
# 添加到历史记录
self.history.append(f"{self.expression} = {result}")
# 更新显示
self.result_var.set(str(result))
self.expression = str(result)
# 更新历史记录标签
self.update_history_label()
except Exception as e:
messagebox.showerror("错误", f"计算错误:{e}")
self.expression = ""
self.result_var.set("0")
def square_root(self):
"""平方根计算"""
if not self.expression:
return
try:
value = float(self.expression)
result = math.sqrt(value)
self.history.append(f"√{self.expression} = {result}")
self.result_var.set(str(result))
self.expression = str(result)
self.update_history_label()
except Exception as e:
messagebox.showerror("错误", f"计算错误:{e}")
def update_history_label(self):
"""更新历史记录显示"""
if self.history:
last = self.history[-1]
self.history_label.config(text=f"历史:{last}")
def show_history(self):
"""显示完整历史记录"""
if not self.history:
messagebox.showinfo("历史记录", "暂无计算记录")
return
history_text = "\n".join(self.history[-10:]) # 显示最近10条
messagebox.showinfo("历史记录", history_text)
def main():
root = tk.Tk()
app = Calculator(root)
root.mainloop()
if __name__ == "__main__":
main()
项目特点:
- GUI编程:使用Tkinter创建图形界面
- 事件驱动:按钮点击事件处理
- 状态管理:维护表达式和结果状态
- 历史记录:记录计算历史
- 错误处理:友好的错误提示
第五阶段:进阶挑战(可选)
5.1 网络编程基础
题目:简易HTTP服务器
完整代码:
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
from datetime import datetime
class SimpleHTTPHandler(BaseHTTPRequestHandler):
"""自定义HTTP请求处理器"""
def do_GET(self):
"""处理GET请求"""
if self.path == "/":
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b"""
<html>
<head><title>简易HTTP服务器</title></head>
<body>
<h1>欢迎访问简易HTTP服务器</h1>
<p>可用端点:</p>
<ul>
<li>GET / - 本页面</li>
<li>GET /api/time - 获取当前时间</li>
<li>GET /api/info - 获取服务器信息</li>
</ul>
</body>
</html>
""")
elif self.path == "/api/time":
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
response = {
"timestamp": datetime.now().isoformat(),
"message": "当前时间"
}
self.wfile.write(json.dumps(response).encode())
elif self.path == "/api/info":
self.send_response(200)
self.send_header('Content-type', 'application/json')
self.end_headers()
response = {
"server": "SimpleHTTPServer/1.0",
"python_version": "3.x",
"timestamp": datetime.now().isoformat()
}
self.wfile.write(json.dumps(response).encode())
else:
self.send_response(404)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(b"404 Not Found")
def log_message(self, format, *args):
"""自定义日志格式"""
print(f"[{self.log_date_time_string()}] {format % args}")
def run_server(port=8000):
"""启动HTTP服务器"""
server_address = ('', port)
httpd = HTTPServer(server_address, SimpleHTTPHandler)
print(f"🚀 服务器启动在 http://localhost:{port}")
print("按 Ctrl+C 停止服务器")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\n🛑 服务器已停止")
httpd.shutdown()
if __name__ == "__main__":
run_server()
使用说明:
- 运行代码:
python server.py - 访问浏览器:
http://localhost:8000 - 测试API:
http://localhost:8000/api/time
5.2 数据分析基础
题目:销售数据分析器
完整代码:
import csv
import json
from collections import defaultdict
from datetime import datetime
class SalesAnalyzer:
"""销售数据分析器"""
def __init__(self, data_file="sales.csv"):
self.data_file = data_file
self.data = []
self.load_data()
def load_data(self):
"""加载销售数据"""
if not os.path.exists(self.data_file):
# 创建示例数据
self.create_sample_data()
with open(self.data_file, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
# 数据类型转换
row['date'] = datetime.strptime(row['date'], '%Y-%m-%d')
row['amount'] = float(row['amount'])
row['quantity'] = int(row['quantity'])
self.data.append(row)
def create_sample_data(self):
"""创建示例数据"""
sample_data = [
{"date": "2024-01-01", "product": "笔记本", "amount": 5000, "quantity": 2, "category": "电子"},
{"date": "2024-01-02", "product": "鼠标", "amount": 150, "quantity": 5, "category": "电子"},
{"date": "2024-01-03", "product": "键盘", "amount": 300, "quantity": 3, "category": "电子"},
{"date": "2024-01-04", "product": "显示器", "amount": 2000, "quantity": 1, "category": "电子"},
{"date": "2024-01-05", "product": "笔记本", "amount": 5000, "quantity": 3, "category": "电子"},
{"date": "2024-01-06", "product": "咖啡", "amount": 50, "quantity": 10, "category": "食品"},
{"date": "2024-01-07", "product": "零食", "amount": 30, "quantity": 15, "category": "食品"},
]
with open(self.data_file, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=["date", "product", "amount", "quantity", "category"])
writer.writeheader()
writer.writerows(sample_data)
print(f"✅ 已创建示例数据:{self.data_file}")
def total_sales(self):
"""总销售额"""
return sum(item['amount'] for item in self.data)
def total_quantity(self):
"""总销售量"""
return sum(item['quantity'] for item in self.data)
def sales_by_category(self):
"""按类别统计"""
result = defaultdict(float)
for item in self.data:
result[item['category']] += item['amount']
return dict(result)
def sales_by_product(self):
"""按产品统计"""
result = defaultdict(float)
for item in self.data:
result[item['product']] += item['amount']
return dict(result)
def monthly_sales(self):
"""按月统计"""
result = defaultdict(float)
for item in self.data]:
month = item['date'].strftime('%Y-%m')
result[month] += item['amount']
return dict(result)
def top_products(self, n=3):
"""Top N 产品"""
products = self.sales_by_product()
return sorted(products.items(), key=lambda x: x[1], reverse=True)[:n]
def generate_report(self):
"""生成完整报告"""
report = {
"总销售额": self.total_sales(),
"总销售量": self.total_quantity(),
"按类别": self.sales_by_category(),
"按产品": self.sales_by_product(),
"按月": self.monthly_sales(),
"Top产品": self.top_products()
}
print("\n" + "="*50)
print("销售数据分析报告")
print("="*50)
print(f"📊 总销售额:{report['总销售额']:.2f}")
print(f"📦 总销售量:{report['总销售量']}")
print("\n按类别:")
for cat, amount in report['按类别'].items():
print(f" {cat}: {amount:.2f}")
print("\n按产品:")
for prod, amount in report['按产品'].items():
print(f" {prod}: {amount:.2f}")
print("\n按月:")
for month, amount in report['按月'].items():
print(f" {month}: {amount:.2f}")
print("\nTop 3 产品:")
for prod, amount in report['Top产品']:
print(f" {prod}: {amount:.2f}")
return report
def main():
analyzer = SalesAnalyzer()
analyzer.generate_report()
if __name__ == "__main__":
main()
学习路径与建议
第一阶段(1-2周):基础语法
- 目标:掌握变量、数据类型、运算符、条件语句、循环、函数
- 练习:每天完成2-3个基础题目
- 重点:理解程序执行流程,培养调试能力
第二阶段(2-3周):数据结构
- 目标:掌握列表、字典、集合、元组,理解算法复杂度
- 练习:每个数据结构至少完成3个练习题
- 重点:空间换时间的思想,不同数据结构的适用场景
第三阶段(2-3周):面向对象
- 目标:理解类与对象、封装、继承、多态
- 练习:重构之前的代码为OOP版本
- 重点:代码复用和模块化设计
第四阶段(3-4周):项目实战
- 目标:综合运用所学知识,完成完整项目
- 练习:至少完成2个完整项目
- 重点:项目架构、错误处理、用户体验
进阶建议
- 代码规范:遵循PEP8,写好注释和文档
- 版本控制:学习使用Git管理代码
- 测试驱动:编写单元测试,保证代码质量
- 持续学习:关注新技术,参与开源项目
常见问题与解决方案
Q1: 代码运行出错怎么办?
A:
- 仔细阅读错误信息,找到出错的行号
- 使用print语句调试变量值
- 使用调试器(如pdb)逐步执行
- 搜索错误信息,参考他人解决方案
Q2: 如何提高编程效率?
A:
- 熟练掌握IDE的快捷键
- 使用代码片段(Snippets)
- 学习标准库和第三方库
- 养成良好的代码组织习惯
Q3: 遇到难题没有思路怎么办?
A:
- 将问题分解为小步骤
- 画流程图或写伪代码
- 参考类似问题的解决方案
- 寻求社区帮助(Stack Overflow、GitHub)
总结
本指南提供了从零基础到项目实战的完整学习路径,涵盖了基础语法、数据结构、面向对象编程和实际项目开发。关键在于坚持练习和动手实践。每个题目都提供了详细的代码示例和解析,建议按照顺序逐步学习,不要急于求成。
记住,编程能力的提升是一个渐进的过程,需要大量的练习和不断的总结。祝你学习顺利,早日成为优秀的程序员!
