Python异常处理与调试进阶 - 老司机带你避坑
写了这么多年Python,发现很多同学还在用print调试代码,看到异常就一脸懵。今天就来聊聊异常处理和调试那些事,顺便分享些实战经验。
异常处理基本功:
try:
risky_operation()
except Exception as e:
print(f"出错了: {e}")
else:
print("操作成功")
finally:
print("清理资源")
光会用try-except可不够,来看个实际案例 - 文件操作异常处理:
def read_config(filepath):
try:
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
config = json.loads(content)
return config
except FileNotFoundError:
logging.error(f"配置文件不存在: {filepath}")
return None
except json.JSONDecodeError as e:
logging.error(f"配置文件格式错误: {e}")
return None
except Exception as e:
logging.error(f"未知错误: {e}")
return None
自定义异常类能让代码更专业:
class ConfigError(Exception):
"""配置相关异常"""
pass
class NetworkError(Exception):
"""网络相关异常"""
def __init__(self, message, status_code=None):
super().__init__(message)
self.status_code = status_code
# 实际使用
def fetch_data(url):
try:
response = requests.get(url)
if response.status_code != 200:
raise NetworkError("请求失败", status_code=response.status_code)
return response.json()
except requests.RequestException as e:
raise NetworkError(f"网络请求异常: {e}")
调试技巧升级版 - 用装饰器记录函数调用:
import functools
import logging
def debug_log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
logging.debug(f"调用 {func.__name__} - 参数: {args}, {kwargs}")
result = func(*args, **kwargs)
logging.debug(f"{func.__name__} 返回值: {result}")
return result
except Exception as e:
logging.error(f"{func.__name__} 异常: {e}")
raise
return wrapper
@debug_log
def divide(a, b):
return a / b
上下文管理器也是处理异常的好帮手;
class DatabaseConnection:
def __init__(self, connection_string):
self.conn_string = connection_string
self.conn = None
def __enter__(self):
try:
self.conn = create_connection(self.conn_string)
return self.conn
except Exception as e:
logging.error(f"数据库连接失败: {e}")
raise
def __exit__(self, exc_type, exc_val, exc_tb):
if self.conn:
self.conn.close()
logging.info("数据库连接已关闭")
return False # 不吞掉异常
# 实际使用
with DatabaseConnection("mysql://localhost/test") as conn:
data = conn.execute("SELECT * FROM users")
调试神器pdb的高级用法:
def complex_calculation(data):
import pdb; pdb.set_trace() # 设置断点
result = []
for item in data:
# 一些复杂操作
processed = process_item(item)
result.append(processed)
return result
# pdb常用命令:
# n (next) - 执行下一行
# s (step) - 步入函数
# c (continue) - 继续执行到下个断点
# p variable - 打印变量值
# l - 显示当前位置代码
性能调试技巧:
import cProfile
import pstats
def profile_code(func):
def wrapper(*args, **kwargs):
profiler = cProfile.Profile()
try:
return profiler.runcall(func, *args, **kwargs)
finally:
stats = pstats.Stats(profiler)
stats.sort_stats('cumulative')
stats.print_stats(20) # 显示前20行性能数据
return wrapper
@profile_code
def expensive_operation():
# 耗时操作
pass
异常处理最佳实践:
只捕获预期的异常,避免捕获所有Exception
异常要尽早抛出,尽晚捕获
保持异常粒度合适,不要过细或过粗
合理使用finally块清理资源
记得记录异常信息,便于后期排查
调试要点:
打日志比print更专业,用logging模块
断点调试配合日志,事半功倍
性能分析工具要会用
单元测试也是调试的好帮手
实战中常见坑点:
异常捕获范围过大,导致bug被掩盖
异常信息记录不完整,难以复现问题
资源未及时释放造成内存泄露
调试代码忘记删除
性能问题定位不准确
掌握这些技巧,代码质量立马提升一个档次。记住,异常处理不是事后补救,而是系统设计的一部分。调试也不是用来找bug的,而是帮助我们理解代码运行机制。
写代码一定要保持工匠精神,异常处理要优雅,调试要专业。有问题就在评论区讨论,一起进步!
领取专属 10元无门槛券
私享最新 技术干货