一、C语言中错误的处理方式
- 用assert来判断一个表达式是否出错;
- 在调用接口函数时,接口函数会设置errno,我们可以通过errno,strerror(errno)来拿到错误码和错误信息。
- 在自定义函数中,我们设置函数错误信息处理的时候,还会采用返回值来处理,这就需要我们来定义一堆的枚举变量来对应不同返回值的错误信息代表;
- 在函数嵌套调用的时候,内层函数出现了问题,就需要外层函数不断通过返回值判断,来查看内层函数是否调用出错,直到在某一个外层函数可以处理错误信息时停止;
二、C++中提供了抛异常的方式
#include <iostream>
void func(int a, int b)
{if(b == 0){throw "除0异常, b不能为0";}std::cout << "a / b = " << a / b << std::endl;
}
int main()
{try{func(1,0);}catch(const char* error){std::cout << error << std::endl;}catch(...) // 捕捉未知异常{std::cout << "Unknown" << std::endl;}std::cout << "END" << std::endl;return 0;
}
三、Python的异常处理
1. 捕获异常的格式
try:内部代码块为可能出错的代码块
except:捕获try代码块中的异常,后跟可能出现的异常,Exception为所有异常,通常放在最后一个except中,保证所有异常都会被捕获
else:表示没有异常出现,执行的代码块
finally:表示无论是否发生异常都会执行的代码块,通常用于执行必要的资源处理:文件描述符的关闭、网络连接的关闭、数据库连接的关闭。避免资源泄露
try:# 执行过程中可能出错的代码块print('try...')n = 10n = n / 1print('result is %d' % n)
except ZeroDivisionError as e: # 捕获指定异常print('except is', e)
except Exception as total: # 捕获所有异常print('except = ', total)
else: # 表示无异常做的事情(可以没有)print('No Exception')
finally: # 表示无论是否发生异常都会执行的代码块(可以没有)print('finally...')
print('END')
【注】:
Python中的异常,都是一个个的类,继承于BaseException这个基类(Exception也是继承的BaseException),所以捕获基类异常时,会将所有子类异常都捕获到。
常见的异常类型与继承关系:
Built-in Exceptions — Python 3.12.4 documentation
2. logging模块记录错误信息
在我们不主动捕获异常的时候,Python解释器会将这个异常捕获,并将错误信息打印在显示器上,如下:
def fun1():n = 10n = n / 0def fun2():fun1()def main():fun2()main()
在Python中可以使用logging模块,在捕获异常中使用,来将Python解释器原本打印在显示器上的错误信息记录到logging中,捕获到异常后,将错误信息与异常一并输出,继续向后执行,最后正常退出
import loggingdef fun1():n = 10n = n / 0def fun2():fun1()def main():fun2()try:main()
except Exception as e:logging.exception(e)
print('END')
3. logging与print在显示器打印的顺序不同的问题
在测试时,
logging
模块的输出顺序可能不同,原因主要在于它们的缓冲机制和输出流的处理方式。logging
模块在默认情况下会立即将日志信息输出。
import loggingdef fun1():n = 10n = n / 0a = 1
try:a = 2fun1()
except Exception as e:logging.exception(e)
print('END a =', a)
这里想说的就是,不要认为是程序执行顺序的问题,代码中a很好的验证了,程序永远都是自顶向下执行的
4. 主动抛出异常raise
在Python中所有的异常类型都是一个个的类,所有我们也可以通过继承的方式来自定义一个异常类型,再使用raise来主动抛出异常。
但自定义异常类型只在必需时使用,其它情况建议使用内置的异常类型即可
class FooError(ValueError):passdef foo(s):n = int(s)if n == 0:raise FooError('value is zero')return 10 / nfoo('0')
5. 异常的重新抛出
主要用于一些函数内部有文件资源的使用、网络连接的使用、数据库资源的使用,不对异常做处理,而是关闭这些资源,再将异常重新抛出给外层,让外层对异常做处理
def foo(s):n = int(s)if n == 0:raise ZeroDivisionError('此时n为0,是不被允许的')return 10 / ndef bar():try:foo('0')except ZeroDivisionError as e:print('except ValueError')raisetry:bar()
except ZeroDivisionError as e:print('真正处理: ', e)