30天学会Python编程:10. Python异常处理与调试

10.1 异常处理基础

10.1.1 异常处理机制

10.1.2 基本语法结构

try:
    # 可能引发异常的代码
except ExceptionType as e:
    # 异常处理代码
else:
    # 无异常时执行
finally:
    # 无论是否异常都执行

10.2 常见异常类型

10.2.1 内置异常层次

10.2.2 主要异常类型

表10-1 Python常见异常类型

异常类型

触发场景

示例

ValueError

值无效

int("abc")

TypeError

类型错误

"a" + 1

IndexError

索引越界

[1,2][3]

KeyError

键不存在

{}["key"]

FileNotFoundError

文件未找到

open("nonexist.txt")

ZeroDivisionError

除零错误

1/0

AttributeError

属性错误

"".no_method()

10.3 异常处理进阶

10.3.1 多异常处理

try:
    # 可能出错的代码
except (ValueError, TypeError) as e:
    print(f"输入错误: {e}")
except FileNotFoundError as e:
    print(f"文件未找到: {e.filename}")
except Exception as e:
    print(f"未知错误: {e}")

10.3.2 异常链与上下文

try:
    import nonexistent_module
except ImportError as e:
    raise RuntimeError("依赖缺失") from e

10.3.3 自定义异常

class MyAppError(Exception):
    """应用基础异常"""
    
class InvalidInputError(MyAppError):
    """输入无效异常"""
    def __init__(self, input_value):
        self.input_value = input_value
        super().__init__(f"无效输入: {input_value}")

# 使用示例
def process(data):
    if not data.isdigit():
        raise InvalidInputError(data)
    return int(data)

10.4 调试技术

10.4.1 print调试法

def complex_calculation(a, b):
    print(f"输入参数: a={a}, b={b}")  # 调试输出
    result = a * b
    print(f"中间结果: {result}")      # 调试输出
    result += 100
    return result

10.4.2 断言调试

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

# 触发断言
divide(10, 0)  # AssertionError: 除数不能为零

10.4.3 logging模块

import logging

# 配置日志
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='app.log'
)

def process_data(data):
    logging.debug(f"开始处理数据: {data}")
    try:
        result = int(data)
        logging.info(f"处理成功: {result}")
        return result
    except ValueError as e:
        logging.error(f"处理失败: {e}")
        raise

10.5 使用调试器

10.5.1 pdb基本命令

表10-2 pdb常用命令

命令

缩写

功能

break

b

设置断点

continue

c

继续执行

next

n

单步执行(不进入函数)

step

s

单步执行(进入函数)

where

w

显示调用栈

print

p

打印变量

list

l

显示当前代码

quit

q

退出调试器

10.5.2 调试示例

# 在代码中插入断点
import pdb; pdb.set_trace()

# 或者命令行启动
# python -m pdb script.py

10.6 单元测试

10.6.1 unittest示例

import unittest

def add(a, b):
    return a + b

class TestAdd(unittest.TestCase):
    def test_add_integers(self):
        self.assertEqual(add(1, 2), 3)
    
    def test_add_strings(self):
        self.assertEqual(add("a", "b"), "ab")
    
    def test_add_type_error(self):
        with self.assertRaises(TypeError):
            add("a", 1)

if __name__ == "__main__":
    unittest.main()

10.6.2 pytest示例

# test_sample.py
import pytest

def test_addition():
    assert 1 + 1 == 2

def test_division():
    with pytest.raises(ZeroDivisionError):
        1 / 0

# 运行测试
# pytest test_sample.py -v

10.7 性能分析

10.7.1 timeit模块

from timeit import timeit

# 测量代码执行时间
time = timeit('"-".join(str(n) for n in range(100))', number=10000)
print(f"执行时间: {time:.4f}秒")

10.7.2 cProfile分析

import cProfile

def slow_function():
    return sum(i*i for i in range(1000000))

cProfile.run('slow_function()')

10.8 综合应用举例

案例1:健壮的数据处理器

import logging
from typing import Union

logging.basicConfig(level=logging.INFO)

class DataProcessor:
    """带有完善错误处理的数据处理器"""
    
    def __init__(self, max_retries=3):
        self.max_retries = max_retries
    
    def process(self, data: Union[str, int, float]) -> float:
        """处理输入数据返回浮点数"""
        for attempt in range(1, self.max_retries + 1):
            try:
                value = float(data)
                if value < 0:
                    logging.warning(f"负值输入: {value}")
                return value
            except (ValueError, TypeError) as e:
                logging.error(f"尝试 {attempt} 失败: {e}")
                if attempt == self.max_retries:
                    raise InvalidInputError(data) from e
                continue
            except Exception as e:
                logging.critical(f"未知错误: {e}")
                raise

# 使用示例
processor = DataProcessor()
try:
    result = processor.process("123.45")
    print(f"处理结果: {result}")
except InvalidInputError as e:
    print(f"处理失败: {e}")

案例2:自动化测试框架

import unittest
from unittest.mock import patch

class TestUserService(unittest.TestCase):
    @patch('user_service.Database')  # 模拟数据库
    def test_user_creation(self, mock_db):
        # 设置模拟返回值
        mock_db.return_value.insert.return_value = 1001
        
        from user_service import create_user
        user_id = create_user("test@example.com", "password123")
        
        # 验证结果
        self.assertEqual(user_id, 1001)
        mock_db.return_value.insert.assert_called_once_with(
            "users", {"email": "test@example.com", "password": "password123"}
        )

    def test_invalid_email(self):
        from user_service import create_user
        with self.assertRaises(ValueError):
            create_user("invalid-email", "password")

if __name__ == "__main__":
    unittest.main()

10.9 学习路线图

10.10 学习总结

  1. 核心要点
  2. 掌握try-except-finally完整结构
  3. 理解异常类继承体系
  4. 熟练使用调试工具
  5. 能够编写单元测试
  6. 实践建议
  7. 异常处理要具体化(避免裸except)
  8. 使用logging替代print调试
  9. 重要操作添加断言检查
  10. 为关键功能编写测试用例
  11. 进阶方向
  12. 异常链与上下文管理
  13. 异步代码调试
  14. 性能优化分析
  15. 测试覆盖率分析
  16. 常见陷阱
  17. 过度捕获异常掩盖问题
  18. 忘记处理finally中的异常
  19. 测试用例不够独立
  20. 调试后遗留的调试代码

持续更新Python编程学习日志与技巧,敬请关注!


#编程# #python# #在头条记录我的2025#


原文链接:,转发请注明来源!