异常与错误处理
本章讲解Cython的异常处理机制。Cython支持Python风格异常和C级错误码,两者的混合使用需要小心处理。
学习路径:异常机制 → C级错误处理 → 自定义异常 → 调试技巧
核心概念:
except *:未知错误处理except -1:返回值指示错误with gil:GIL区域内抛出Python异常
10.1 Cython异常机制
Section titled “10.1 Cython异常机制”raise语句
Section titled “raise语句”功能说明:使用raise抛出Python异常。
# Python风格异常def raise_error(): raise ValueError("Invalid value")
# Cython中也可以cpdef void check_positive(int x) except *: if x < 0: raise ValueError("x must be positive")输出示例:
>>> check_positive(-1)ValueError: x must be positiveexcept关键字
Section titled “except关键字”功能说明:声明函数如何处理异常。
# except * - 未知错误时设置Python异常cdef int risky() except *: # 如果函数返回时存在待处理的异常,设置Python异常 return might_fail()
# except -1 - 返回-1时设置异常(仅对有符号整数)cdef int risky2() except -1: return might_fail()
# except? - 返回值可能无效(条件异常)cdef int conditional() except? -1: return might_return_neg()说明:
| 声明 | 行为 |
|---|---|
except * | 函数返回后检查异常 |
except -1 | 返回-1时设置异常 |
except? -1 | 可能返回-1,不确定 |
功能说明:异常自动从cdef函数传播到Python调用者。
# 异常自动传播cdef void outer(): inner() # 如果inner()抛出异常,会自动传播
cdef void inner(): raise RuntimeError("Error from inner")
# 测试try: outer()except RuntimeError as e: print(f"Caught: {e}")输出示例:
>>> outer()RuntimeError: Error from inner10.2 C级错误处理
Section titled “10.2 C级错误处理”C异常到Python异常
Section titled “C异常到Python异常”功能说明:将C函数错误码转换为Python异常。
# C函数返回错误码cdef extern from "math.h": double sqrt(double) int isnan(double)
cdef double safe_sqrt(double x) except *: if isnan(x): raise ValueError("Cannot sqrt NaN") if x < 0: raise ValueError("Cannot sqrt negative") return sqrt(x)check布尔检查
Section titled “check布尔检查”功能说明:条件检查后抛出异常。
# 使用条件检查cdef int divide(int a, int b) except *: if b == 0: raise ZeroDivisionError("division by zero") return a // b
# 快速检查宏(不抛异常)cdef int checked_divide(int a, int b): return a // b if b != 0 else 0功能说明:确保异常发生时资源正确释放。
# 异常安全的资源管理cdef class SafeResource: cdef void* _handle
def __cinit__(self): self._handle = allocate() if self._handle == NULL: raise MemoryError("Failed to allocate")
def __dealloc__(self): if self._handle != NULL: deallocate(self._handle)
# try-finally模式(异常安全)cdef void raii_pattern() except *: cdef double* data = <double*>malloc(100 * sizeof(double)) if data == NULL: raise MemoryError() try: process_data(data, 100) finally: free(data)最佳实践:使用RAII模式管理资源,异常发生时自动释放。
10.3 自定义异常
Section titled “10.3 自定义异常”功能说明:定义Python异常类用于特定错误。
# 定义Cython异常类class MyError(Exception): """Custom error for my module""" def __init__(self, str message, int code=0): self.code = code super().__init__(message)
# 使用cpdef void validate(int value) except *: if value < 0: raise MyError("Value cannot be negative", code=1001)输出示例:
>>> validate(-1)MyError: Value cannot be negative功能说明:异常类可包含额外属性。
class ConfigError(Exception): cdef str _key cdef str _value
def __init__(self, str key, str message): self._key = key self._value = message super().__init__(f"{key}: {message}")
property key: def __get__(self): return self._key
property value: def __get__(self): return self._value
cpdef void load_config(str key) except *: if key == "invalid": raise ConfigError(key, "Key is invalid")异常层次结构
Section titled “异常层次结构”功能说明:异常可以组织成层次结构。
# 异常层次class ValidationError(Exception): pass
class RangeError(ValidationError): pass
class TypeError(ValidationError): pass
cpdef void validate_range(int x, int min_val, max_val) except *: if x < min_val or x > max_val: raise RangeError(f"{x} not in range [{min_val}, {max_val}]")
cpdef void validate_type(x, expected_type) except *: if not isinstance(x, expected_type): raise TypeError(f"Expected {expected_type}, got {type(x)}")10.4 调试技巧
Section titled “10.4 调试技巧”功能说明:使用annotate分析生成的C代码。
# 查看生成的C代码# bash: cython -a mymodule.pyx# 会生成mymodule.html - 黄色区域需要优化
# 使用assert(仅debug模式)cdef void debug_version(int x) except *: assert x >= 0, "x must be non-negative" # 正常逻辑功能说明:print语句和C级printf。
# Python风格printcdef void debug_print(): cdef int x = 10 print(f"Debug: x = {x}")
# C级printf(无GIL开销)cdef void debug_cprint(): cimport libc.stdio as stdio stdio.printf("C debug: %d\n", 10)
# pdb调试# pyximport.install()# import pdb; pdb.set_trace()功能说明:使用GDB调试生成的C代码。
# 生成调试信息cython -a module.pyxgcc -g -I/usr/include/python3.10 module.c -o module.so
# GDB调试gdb python(gdb) break module.c:123(gdb) run test.py异常机制对比
Section titled “异常机制对比”| 机制 | 用途 |
|---|---|
except * | 未知错误处理 |
except -1 | 返回值指示错误 |
except? -1 | 可选错误处理 |
raise | 抛出Python异常 |
with gil | GIL区域内抛异常 |
try-finally | 异常安全的清理 |
最佳实践清单
Section titled “最佳实践清单”- 使用
except *处理可能返回错误的函数 - 资源分配在
__cinit__中,异常在__dealloc__中释放 - 避免在
nogil块中抛异常(先用with gil) - 用
assert进行开发期检查,生产用条件检查
- 实现一个安全的除法函数,处理除零情况
- 创建自定义异常类
ProcessingError,包含错误码和消息 - 使用try-except处理C级内存分配失败
- 使用cython -a分析代码,识别黄色热点区域
- 实现RAII模式的资源管理类
- 用GDB调试生成的C代码,设置断点查看变量