30天学会Python编程:12. Python异常处理与调试
当前位置:点晴教程→知识管理交流
→『 技术文档交流 』
|
ValueError | |||
TypeError | |||
IndexError | |||
KeyError | |||
FileNotFoundError | |||
ZeroDivisionError | |||
AttributeError |
实践建议:
try:
with open("data.json", "r") as f:
data = json.load(f)
value = data["key"][5]
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"文件错误: {e}")
except (KeyError, IndexError) as e:
print(f"数据访问错误: {e}")
except Exception as e:
print(f"未知错误: {e}")
# 记录日志并重新抛出
logging.exception("处理失败")
raise
技巧:
try:
import third_party_module
except ImportError as e:
raise RuntimeError("缺少必要依赖") from e
应用场景举例:
class AppError(Exception):
"""应用基础异常"""
classInvalidInputError(AppError):
"""输入无效异常"""
def__init__(self, input_value, message="无效输入"):
self.input_value = input_value
super().__init__(f"{message}: {input_value}")
# 使用示例
defvalidate_email(email):
if"@"notin email:
raise InvalidInputError(email, "邮箱格式错误")
return email
设计原则:
def calculate(a, b):
print(f"[DEBUG] 输入: a={a}, b={b}")
result = a / b
print(f"[DEBUG] 中间结果: {result}")
return result * 100
适用场景:
局限性:
def withdraw(account, amount):
assert amount > 0, "取款金额必须大于0"
assert amount <= account.balance, "余额不足"
account.balance -= amount
return account.balance
实践建议:
import logging
# 配置日志系统
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='app.log'
)
logger = logging.getLogger(__name__)
defprocess_data(data):
logger.debug(f"开始处理数据: {data}")
try:
result = complex_operation(data)
logger.info(f"处理成功: {result}")
return result
except ValueError as e:
logger.error(f"处理失败: {e}", exc_info=True)
raise
日志级别:
优势:
# script.py
def factorial(n):
result = 1
for i in range(1, n+1): # 在此行设置断点
result *= i
return result
if __name__ == "__main__":
import pdb; pdb.set_trace() # 启动调试器
print(factorial(5))
调试流程:
python script.py
p n
, p result
n
或s
c
替代方案:
import unittest
defdivide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
classTestMathOperations(unittest.TestCase):
deftest_divide_normal(self):
self.assertEqual(divide(10, 2), 5)
deftest_divide_zero(self):
withself.assertRaises(ValueError) as context:
divide(10, 0)
self.assertEqual(str(context.exception), "除数不能为零")
@unittest.skip("待实现")
deftest_negative_division(self):
pass
if __name__ == "__main__":
unittest.main()
# test_math.py
import pytest
deftest_addition():
assert1 + 1 == 2
deftest_division_by_zero():
with pytest.raises(ValueError, match="除数不能为零"):
divide(10, 0)
@pytest.mark.parametrize("a,b,expected", [
(10, 2, 5),
(20, 4, 5),
(15, 3, 5)
])
deftest_divide_cases(a, b, expected):
assert divide(a, b) == expected
测试实践:
from timeit import timeit
# 测量列表推导式性能
list_comp_time = timeit('[x**2 for x in range(1000)]', number=10000)
# 测量生成器表达式性能
gen_exp_time = timeit('(x**2 for x in range(1000))', number=10000)
print(f"列表推导: {list_comp_time:.4f}秒")
print(f"生成器表达式: {gen_exp_time:.4f}秒")
import cProfile
def process_data():
# 模拟数据处理
data = [i**2 for i in range(10000)]
return sum(data) / len(data)
# 运行性能分析
cProfile.run('process_data()', sort='cumulative')
分析要点:
优化策略:
import logging
from typing importUnion
classDataProcessor:
"""带有完善错误处理的数据处理器"""
def__init__(self, max_retries=3):
self.max_retries = max_retries
defprocess(self, data: Union[str, int, float]) -> float:
"""处理输入数据返回浮点数"""
for attempt inrange(1, self.max_retries + 1):
try:
value = float(data)
logging.info(f"成功转换: {data} -> {value}")
return value
except (ValueError, TypeError) as e:
logging.warning(f"尝试 {attempt} 失败: {e}")
if attempt == self.max_retries:
raise InvalidInputError(data) from e
except Exception as e:
logging.error(f"未知错误: {e}")
raise
设计解释:
优秀的程序员不是不犯错误,而是知道如何高效地处理错误并从中学习。
掌握异常处理和调试技能,能使我们从普通开发者蜕变为专业的Python开发者。持续练习,编写更健壮、更可靠的Python应用程序!
阅读原文:原文链接