Python学习笔记:错误和异常处理

1. 什么是错误和异常

在Python中,错误可以分为两类:

  • 语法错误(Syntax Errors):代码不符合Python语法规则
  • 异常(Exceptions):语法正确的代码在运行时发生的错误
python 复制代码
# 语法错误示例
print("Hello World"  # 缺少右括号

# 异常示例
print(10 / 0)  # ZeroDivisionError: division by zero

2. 常见的异常类型

Python内置了许多异常类型,常见的有:

python 复制代码
# NameError - 尝试访问未定义的变量
print(undefined_variable)

# TypeError - 类型操作错误
"2" + 2  # 不能将字符串和整数相加

# IndexError - 索引超出范围
lst = [1, 2, 3]
print(lst[3](@ref)

# KeyError - 字典键不存在
d = {'a': 1}
print(d['b'])

# FileNotFoundError - 文件不存在
open('nonexistent.txt')

3. 异常处理:try-except语句

使用try-except可以捕获并处理异常:

python 复制代码
try:
    # 可能引发异常的代码
    result = 10 / 0
except ZeroDivisionError:
    # 处理特定异常
    print("不能除以零!")

捕获多种异常

python 复制代码
try:
    num = int(input("请输入一个数字: "))
    result = 100 / num
    print("结果是:", result)
except ValueError:
    print("输入的不是有效数字!")
except ZeroDivisionError:
    print("不能输入零!")
except Exception as e:  # 捕获所有其他异常
    print(f"发生未知错误: {e}")

4. try-except-else-finally完整结构

python 复制代码
try:
    file = open('example.txt', 'r')
    content = file.read()
except FileNotFoundError:
    print("文件不存在!")
else:
    # 如果没有异常发生,执行else块
    print("文件内容:", content)
finally:
    # 无论是否发生异常都会执行
    print("清理工作...")
    if 'file' in locals() and not file.closed:
        file.close()

5. 抛出异常:raise语句

我们可以主动抛出异常:

python 复制代码
def check_age(age):
    if age < 0:
        raise ValueError("年龄不能为负数")
    elif age < 18:
        raise ValueError("未成年禁止访问")
    else:
        print("欢迎访问")

try:
    check_age(-5)
except ValueError as e:
    print(f"错误: {e}")

6. 自定义异常

我们可以创建自己的异常类型:

python 复制代码
class MyCustomError(Exception):
    """自定义异常类 - 用于演示特定业务场景的错误"""
    def __init__(self, message, error_code=500):
        self.message = message
        self.error_code = error_code
        super().__init__(f"错误代码 {error_code}: {message}")

    def __str__(self):
        """自定义异常信息的字符串表示形式"""
        return f"[{self.__class__.__name__}] {self.message}"


def calculate_division(dividend, divisor):
    """演示函数:执行除法运算,当条件不满足时抛出不同类型的异常"""
    if not isinstance(dividend, (int, float)) or not isinstance(divisor, (int, float)):
        raise TypeError("被除数和除数必须是数字类型")
    
    if divisor == 0:
        raise ZeroDivisionError("除数不能为零")
    
    if dividend < 0 or divisor < 0:
        # 抛出自定义异常:当输入为负数时
        raise MyCustomError("计算不支持负数输入", error_code=400)
    
    return dividend / divisor


def main():
    """主函数:演示异常的捕获和处理流程"""
    print("=== 自定义异常演示程序 ===")
    
    while True:
        try:
            # 获取用户输入
            num1 = float(input("\n请输入被除数(输入q退出):"))
            num2 = float(input("请输入除数:"))
            
            # 执行计算
            result = calculate_division(num1, num2)
            print(f"计算结果:{num1} ÷ {num2} = {result}")
        
        except ValueError as e:
            # 处理非数字输入
            if "q" in str(e).lower():
                print("程序已退出")
                break
            print(f"输入错误:请输入有效的数字。错误详情:{e}")
        
        except ZeroDivisionError as e:
            # 处理内置异常
            print(f"数学错误:{e}")
        
        except MyCustomError as e:
            # 处理自定义异常
            print(f"业务错误:{e}(错误代码:{e.error_code})")
        
        except TypeError as e:
            # 处理类型错误
            print(f"类型错误:{e}")
        
        except Exception as e:
            # 捕获所有其他未预期的异常
            print(f"未知错误:{e}")
            break


if __name__ == "__main__":
    main()    

这个示例程序包含以下关键特性:

  1. 自定义异常类 :MyCustomError继承自Exception,包含错误信息和错误代码
  2. 异常抛出函数 :calculate_division根据不同条件抛出不同类型的异常
  3. 多级异常捕获 :在main函数中使用多个except块分别处理不同类型的异常
  4. 用户交互:通过控制台输入演示异常的触发和处理流程
    你可以运行这段代码并尝试以下输入场景:
  • 正常输入两个正数(如10和2)
  • 输入零作为除数(触发ZeroDivisionError)
  • 输入负数(触发MyCustomError)
  • 输入非数字字符(触发ValueError)
  • 输入q退出程序

通过观察不同输入下的输出结果,你可以深入理解自定义异常的工作机制和优势。

7. 断言assert

assert用于确保某个条件为真,否则抛出AssertionError:

python 复制代码
def divide(a, b):
    assert b != 0, "除数不能为零"
    return a / b

print(divide(10, 2))  # 正常
print(divide(10, 0))  # 抛出AssertionError

8. 实际应用案例

案例1:处理用户输入

python 复制代码
while True:
    try:
        age = int(input("请输入您的年龄: "))
        if age < 0:
            raise ValueError("年龄不能为负数")
        break
    except ValueError as e:
        print(f"无效输入: {e}")

print(f"您的年龄是: {age}")

案例2:文件操作

python 复制代码
def read_file(filename):
    try:
        with open(filename, 'r') as file:
            return file.read()
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
        return None
    except IOError:
        print(f"读取文件 {filename} 时发生错误")
        return None

content = read_file('data.txt')
if content:
    print("文件内容:", content)

案例3:网络请求

python 复制代码
import requests

def fetch_url(url):
    try:
        response = requests.get(url, timeout=5)
        response.raise_for_status()  # 如果请求不成功,抛出HTTPError
        return response.text
    except requests.exceptions.Timeout:
        print("请求超时")
    except requests.exceptions.HTTPError as err:
        print(f"HTTP错误: {err}")
    except requests.exceptions.RequestException as err:
        print(f"请求错误: {err}")
    return None

html = fetch_url("https://www.example.com")
if html:
    print("获取内容成功!")

9. 异常处理的最佳实践

  1. 1.不要过度使用try-except:只捕获你知道如何处理的异常
  2. 2.尽量具体:捕获特定异常而不是通用的Exception
  3. 3.记录异常信息:使用logging模块记录异常详情
  4. 4.保持简洁:try块中只包含可能引发异常的代码
  5. 5.清理资源:使用finally或上下文管理器(with语句)确保资源释放
python 复制代码
import logging

logging.basicConfig(filename='app.log', level=logging.ERROR)

def process_data(data):
    try:
        # 只包含可能引发异常的代码
        result = complex_operation(data)
    except ValueError as e:
        logging.error(f"处理数据时发生值错误: {e}")
        return None
    except DatabaseError as e:
        logging.error(f"数据库错误: {e}")
        return None
    else:
        return result

10. 总结

异常处理是Python编程中非常重要的部分,合理使用异常处理可以使程序:

  • 更加健壮,能够处理意外情况
  • 更易于调试和维护
  • 提供更好的用户体验

异常处理不是用来隐藏错误的,而是为了优雅地处理错误情况!

相关推荐
quantdash_cc5 分钟前
如何验证历史行情的交易日期是否完整覆盖研究区间?
python·数据分析·pandas·量化交易·股票数据·quantdash
I Am a robert girl5 分钟前
当智能体学会“串通”:从长程交互中读懂涌现式合谋
python·多智能体系统·多智能体协作·llm agent·涌现式合谋·对齐问题·激励机制设计
Raas10022 分钟前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
云和数据.ChenGuang1 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain
一木 之林1 小时前
Dify学习笔记 03 · RAG检索增强生成:三代范式、评估与落地(第40-45、55-56集)
笔记·小程序·交互·dify
专注仿真1 小时前
线性回归和逻辑回归算法详解
开发语言·人工智能·python·大模型训练·控制算法
apple-mapping2 小时前
网络RTK定位学习总结
学习·网络rtk
jimy12 小时前
C++ 中的 `T&&`:右值引用与转发引用
开发语言·c++
呆呆虫122 小时前
用 orjson 加速 SerpBase 响应解析:基准对比与注意事项
开发语言·php
wflynn2 小时前
GitHub 今日推荐|Edge0:让大号 MoE 模型在一台 Mac 上流式跑起来
python·开源·github