异常(Exceptions)是程序在运行过程中出现的意外情况,它会干扰程序的正常执行流程。比如:
尝试打开一个不存在的文件
用0去除一个数
访问不存在的列表元素
把一个字符串转换为整数时字符串不符合数字格式
# 常见的异常示例print(10 / 0) # ZeroDivisionError: division by zeronumbers = [1, 2, 3]print(numbers[5]) # IndexError: list index out of rangefile = open("nonexistent.txt") # FileNotFoundError: [Errno 2] No such file or directory
:友好的错误提示比程序崩溃要好
:即使出现问题,程序也能继续运行或优雅退出
:确保文件、网络连接等资源能正确释放
异常可以通过两种方式引发:
当程序执行到无法继续的情况时,Python会自动抛出异常:
# 示例1:除零错误def divide(a, b): return a / bdivide(10, 0) # Python自动引发ZeroDivisionError# 示例2:类型错误"10" + 10 # Python自动引发TypeError
我们可以使用raise
关键字主动抛出异常:
# 示例1:验证输入def validate_age(age): if age < 0: raise ValueError("年龄不能为负数") elif age > 120: raise ValueError("年龄不合理,请检查输入")# 调用示例try: validate_age(-5)except ValueError as e: print(f"输入错误: {e}")
try: # 可能引发异常的代码 result = 10 / 0except ZeroDivisionError: # 处理异常的代码 print("不能除以零!")
try: # 可能有多种异常的代码 number = int(input("请输入一个整数: ")) result = 10 / number print(f"结果是: {result}")except ValueError: print("输入的不是有效的整数!")except ZeroDivisionError: print("不能输入零!")
try: # 可能有多种异常的代码 file = open("data.txt") data = file.read() print(data)except Exception as e: # 捕获所有异常 print(f"发生错误: {e}")finally: if 'file' in locals(): file.close()
⚠️ 注意:在实际开发中,应该尽量具体地捕获异常,而不是笼统地捕获Exception
。
finally
语句块定义了一段无论如何都要执行的代码,无论是否发生异常。
:关闭文件、释放锁、断开网络连接等
:无论成功还是失败都需要执行的操作
def process_file(filename): file = None try: file = open(filename, 'r') content = file.read() # 这里可能有很多处理逻辑 processed = content.upper() return processed except FileNotFoundError: print(f"文件 {filename} 不存在") except PermissionError: print(f"没有权限读取文件 {filename}") except Exception as e: print(f"处理文件时发生未知错误: {e}") finally: if file is not None: # 确保file存在 file.close() print("文件处理完成")# 测试result = process_file("example.txt")print(result if result else "")
如果没有异常发生:try块 → finally块
如果发生异常被捕获:try块 → except块 → finally块
如果发生异常未被捕获:try块 → finally块 → 抛出异常
让我们看一个完整的实践案例:
def get_user_info(): user_data = {} try: # 获取姓名 name = input("请输入您的姓名: ") if not name: raise ValueError("姓名不能为空") # 获取年龄 age_input = input("请输入您的年龄: ") age = int(age_input) if age < 0 or age > 120: raise ValueError("年龄必须在0-120之间") # 获取喜欢的数字 favorite_num_input = input("请输入您最喜欢的数字: ") favorite_num = float(favorite_num_input) # 计算结果 score = age * 1.0 / favorite_num # 构建用户数据 user_data = { "name": name, "age": age, "favorite_num": favorite_num, "score": score } except ValueError as ve: print(f"输入错误: {ve}") except ZeroDivisionError: print("最喜欢的数字不能为零!") except Exception as e: print(f"发生未知错误: {e}") finally: print("感谢您的参与!") return user_datadef save_user_data(user_data, filename="user_data.txt"): try: with open(filename, 'a') as file: file.write(str(user_data) + "\n") print("数据保存成功!") except IOError as e: print(f"保存数据时出错: {e}") except Exception as e: print(f"发生未知错误: {e}")# 主程序def main(): while True: user_info = get_user_info() if user_info: # 如果有有效数据 save_user_data(user_info) choice = input("是否继续输入? (y/n): ").lower() if choice != 'y': print("程序结束!") breakif __name__ == "__main__": main()
在这个案例中,我们实现了:
处理多种用户输入异常
使用finally确保始终显示感谢信息
安全地保存数据到文件
友好的用户交互体验
:不要笼统使用except Exception
:使用logging模块记录完整的错误信息
:用finally或上下文管理器(with)确保资源释放
:为应用特定错误创建自定义异常
:至少记录异常信息,除非有充分理由
# 自定义异常示例class InvalidPasswordError(Exception): """密码不符合要求的异常""" def __init__(self, message="密码必须至少包含8个字符和1个数字"): self.message = message super().__init__(self.message)def validate_password(password): if len(password) < 8 or not any(c.isdigit() for c in password): raise InvalidPasswordError()try: validate_password("weak")except InvalidPasswordError as e: print(f"密码无效: {e}")