欢迎回来!🎉 这节课我们要学习如何处理程序运行时可能出现的错误和异常,让我们的程序更健壮、更稳定!
前七节课我们学会了: - 变量和基本数据类型 - 条件判断和循环 - 列表和字典 - 函数(代码的魔法师) - 文件操作(数据持久化) - 模块和包(代码组织) - 面向对象编程(OOP)
这节课我们要学习如何优雅地处理错误!
语法错误(Syntax Error):代码写错了,Python根本无法运行
异常(Exception):代码语法正确,但运行时出现了问题
# ZeroDivisionError:除以零
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"错误:{e}")
# NameError:使用未定义的变量
try:
print(undefined_variable)
except NameError as e:
print(f"错误:{e}")
# TypeError:类型错误
try:
result = "10" + 5
except TypeError as e:
print(f"错误:{e}")
# ValueError:值错误
try:
num = int("abc")
except ValueError as e:
print(f"错误:{e}")
# IndexError:索引超出范围
try:
lst = [1, 2, 3]
print(lst[10])
except IndexError as e:
print(f"错误:{e}")
# KeyError:字典键不存在
try:
d = {"name": "小明"}
print(d["age"])
except KeyError as e:
print(f"错误:{e}")
# FileNotFoundError:文件不存在
try:
with open("不存在的文件.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
print(f"错误:{e}")
# AttributeError:属性不存在
try:
s = "hello"
s.nonexistent_method()
except AttributeError as e:
print(f"错误:{e}")
try:
# 可能出错的代码
result = 10 / 0
except ZeroDivisionError:
# 捕获到异常时执行
print("不能除以零!")
try:
num = int(input("请输入一个数字:"))
result = 100 / num
print(f"结果是:{result}")
except ValueError:
print("请输入有效的数字!")
except ZeroDivisionError:
print("不能除以零!")
except Exception as e:
print(f"发生了未知错误:{e}")
try:
with open("test.txt", "r") as f:
content = f.read()
except FileNotFoundError as e:
print(f"文件不存在:{e}")
print(f"错误类型:{type(e).__name__}")
try:
num = int(input("请输入一个数字:"))
except ValueError:
print("请输入有效的数字!")
else:
# 没有异常时执行
print(f"你输入的数字是:{num}")
print(f"数字的平方是:{num ** 2}")
try:
f = open("test.txt", "r")
content = f.read()
print("文件读取成功!")
except FileNotFoundError:
print("文件不存在!")
finally:
# 无论是否有异常都会执行
print("执行清理工作...")
# f.close() # 注意:如果文件没打开成功,这里会报错
try:
# 尝试执行的代码
num = int(input("请输入一个数字:"))
result = 10 / num
except ValueError:
# 处理ValueError
print("请输入有效的整数!")
except ZeroDivisionError:
# 处理ZeroDivisionError
print("不能除以零!")
except Exception as e:
# 处理其他所有异常
print(f"发生了错误:{e}")
else:
# 没有异常时执行
print(f"计算成功!10 / {num} = {result}")
finally:
# 无论如何都执行
print("程序执行完毕!")
def divide(a, b):
if b == 0:
# 抛出异常
raise ValueError("除数不能为零!")
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
raise TypeError("参数必须是数字!")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f"错误:{e}")
try:
result = divide("10", 2)
except TypeError as e:
print(f"错误:{e}")
def process_data(data):
try:
result = int(data)
return result
except ValueError as e:
print(f"处理数据时出错:{e}")
# 重新抛出异常,让上层处理
raise
try:
process_data("abc")
except ValueError:
print("上层捕获到异常")
# 自定义异常基类
class MyError(Exception):
"""我的自定义异常基类"""
pass
# 具体的异常类
class InvalidAgeError(MyError):
"""年龄无效异常"""
def __init__(self, age, message="年龄必须在0-150之间"):
self.age = age
self.message = message
super().__init__(self.message)
def __str__(self):
return f"{self.message},你输入的是:{self.age}"
class InsufficientBalanceError(MyError):
"""余额不足异常"""
def __init__(self, balance, amount, message="余额不足"):
self.balance = balance
self.amount = amount
self.message = message
super().__init__(self.message)
def __str__(self):
return f"{self.message}!需要:{self.amount},当前余额:{self.balance}"
# 使用自定义异常
class Person:
def __init__(self, name, age):
self.name = name
if not (0 <= age <= 150):
raise InvalidAgeError(age)
self.age = age
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientBalanceError(self.balance, amount)
self.balance -= amount
print(f"取款成功!剩余余额:{self.balance}")
# 测试
try:
person = Person("小明", 200)
except InvalidAgeError as e:
print(e)
try:
account = BankAccount(100)
account.withdraw(200)
except InsufficientBalanceError as e:
print(e)
def load_config():
try:
with open("config.json", "r") as f:
return f.read()
except FileNotFoundError as e:
# 异常链:从e引发新的异常
raise RuntimeError("无法加载配置文件") from e
try:
load_config()
except RuntimeError as e:
print(f"错误:{e}")
print(f"原因:{e.__cause__}")
def func():
try:
1 / 0
except:
raise ValueError("出错了") # 隐式保留原始异常
try:
func()
except ValueError as e:
print(f"捕获到:{e}")
print(f"上下文:{e.__context__}")
# 不好的做法:捕获所有异常
try:
# 一些代码
pass
except:
print("出错了") # 不知道是什么错误
# 好的做法:只捕获特定异常
try:
with open("file.txt", "r") as f:
content = f.read()
except FileNotFoundError:
print("文件不存在,请检查文件路径")
# 不好的做法
try:
int(input("输入数字:"))
except:
print("错误")
# 好的做法
try:
user_input = input("输入数字:")
num = int(user_input)
except ValueError:
print(f"错误:'{user_input}' 不是有效的整数,请重新输入")
# 方法1:try-finally
file = None
try:
file = open("data.txt", "r")
content = file.read()
finally:
if file:
file.close()
# 方法2:with语句(推荐)
with open("data.txt", "r") as file:
content = file.read()
# 不好的做法:用异常控制流程
def get_item(dictionary, key):
try:
return dictionary[key]
except KeyError:
return None
# 好的做法:先检查
def get_item(dictionary, key):
if key in dictionary:
return dictionary[key]
return None
# 或者使用get方法
value = dictionary.get(key, None)
让我们创建一个完善的用户管理系统,包含各种异常处理!
import re
from datetime import datetime
# 自定义异常
class UserManagementError(Exception):
"""用户管理异常基类"""
pass
class InvalidUsernameError(UserManagementError):
"""用户名无效异常"""
pass
class InvalidEmailError(UserManagementError):
"""邮箱无效异常"""
pass
class InvalidPasswordError(UserManagementError):
"""密码无效异常"""
pass
class UserNotFoundError(UserManagementError):
"""用户不存在异常"""
pass
class UserAlreadyExistsError(UserManagementError):
"""用户已存在异常"""
pass
# 用户类
class User:
def __init__(self, username, email, password):
self.username = self._validate_username(username)
self.email = self._validate_email(email)
self.password = self._validate_password(password)
self.created_at = datetime.now()
self.is_active = True
def _validate_username(self, username):
"""验证用户名"""
if not username:
raise InvalidUsernameError("用户名不能为空")
if len(username) < 3:
raise InvalidUsernameError("用户名长度不能少于3个字符")
if len(username) > 20:
raise InvalidUsernameError("用户名长度不能超过20个字符")
if not username.isalnum():
raise InvalidUsernameError("用户名只能包含字母和数字")
return username
def _validate_email(self, email):
"""验证邮箱"""
if not email:
raise InvalidEmailError("邮箱不能为空")
# 简单的邮箱正则
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, email):
raise InvalidEmailError(f"邮箱格式无效:{email}")
return email
def _validate_password(self, password):
"""验证密码"""
if not password:
raise InvalidPasswordError("密码不能为空")
if len(password) < 6:
raise InvalidPasswordError("密码长度不能少于6个字符")
# 检查是否包含至少一个字母和一个数字
has_letter = any(c.isalpha() for c in password)
has_digit = any(c.isdigit() for c in password)
if not has_letter:
raise InvalidPasswordError("密码必须包含至少一个字母")
if not has_digit:
raise InvalidPasswordError("密码必须包含至少一个数字")
return password
def __str__(self):
return f"User(username='{self.username}', email='{self.email}', active={self.is_active})"
# 用户管理器
class UserManager:
def __init__(self):
self.users = {} # username -> User
def add_user(self, username, email, password):
"""添加用户"""
if username in self.users:
raise UserAlreadyExistsError(f"用户 '{username}' 已存在")
try:
user = User(username, email, password)
self.users[username] = user
print(f"✅ 用户 '{username}' 创建成功!")
return user
except (InvalidUsernameError, InvalidEmailError, InvalidPasswordError) as e:
print(f"❌ 创建用户失败:{e}")
raise
def get_user(self, username):
"""获取用户"""
if username not in self.users:
raise UserNotFoundError(f"用户 '{username}' 不存在")
return self.users[username]
def update_email(self, username, new_email):
"""更新邮箱"""
user = self.get_user(username)
try:
user.email = user._validate_email(new_email)
print(f"✅ 用户 '{username}' 邮箱更新成功!")
except InvalidEmailError as e:
print(f"❌ 更新邮箱失败:{e}")
raise
def update_password(self, username, old_password, new_password):
"""更新密码"""
user = self.get_user(username)
if user.password != old_password:
raise InvalidPasswordError("原密码不正确")
try:
user.password = user._validate_password(new_password)
print(f"✅ 用户 '{username}' 密码更新成功!")
except InvalidPasswordError as e:
print(f"❌ 更新密码失败:{e}")
raise
def delete_user(self, username):
"""删除用户"""
if username not in self.users:
raise UserNotFoundError(f"用户 '{username}' 不存在")
del self.users[username]
print(f"✅ 用户 '{username}' 删除成功!")
def list_users(self):
"""列出所有用户"""
if not self.users:
print("当前没有用户")
return
print("\n=== 用户列表 ===")
for i, (username, user) in enumerate(self.users.items(), 1):
print(f"{i}. {user}")
# 主程序
def main():
print("="*60)
print(" 👥 用户管理系统")
print("="*60)
manager = UserManager()
# 演示各种操作
print("\n--- 1. 添加用户 ---")
try:
manager.add_user("xiaoming", "xiaoming@example.com", "password123")
manager.add_user("xiaohong", "xiaohong@example.com", "secure456")
manager.add_user("invalid", "bad-email", "short") # 这个会失败
except UserManagementError as e:
print(f"操作失败:{e}")
print("\n--- 2. 列出用户 ---")
manager.list_users()
print("\n--- 3. 查询用户 ---")
try:
user = manager.get_user("xiaoming")
print(f"找到用户:{user}")
except UserNotFoundError as e:
print(e)
print("\n--- 4. 更新邮箱 ---")
try:
manager.update_email("xiaoming", "xiaoming_new@example.com")
manager.update_email("xiaohong", "invalid-email") # 失败
except UserManagementError as e:
print(e)
print("\n--- 5. 更新密码 ---")
try:
manager.update_password("xiaoming", "password123", "newpass789")
manager.update_password("xiaohong", "wrongpassword", "newpass") # 失败
except UserManagementError as e:
print(e)
print("\n--- 6. 删除用户 ---")
try:
manager.delete_user("xiaohong")
manager.delete_user("nonexistent") # 失败
except UserManagementError as e:
print(e)
print("\n--- 7. 最终用户列表 ---")
manager.list_users()
print("\n" + "="*60)
print(" 🎉 演示完成!")
print("="*60)
if __name__ == "__main__":
main()
今天我们学会了:
✅ 异常的概念:运行时出现的问题
✅ 常见异常类型:ZeroDivisionError、ValueError、KeyError等
✅ try-except语句:捕获和处理异常
✅ else和finally:无异常时执行,无论如何都执行
✅ 抛出异常:raise语句
✅ 自定义异常:创建自己的异常类
✅ 异常链:保留异常上下文
✅ 最佳实践:合理使用异常,提供有用信息
下节课预告:我们会学习正则表达式,强大的文本处理工具!
继续加油!你已经掌握了Python编程的核心技能!💪