Python的异常处理(与C++对比学习)

一、C语言中错误的处理方式

  1. 用assert来判断一个表达式是否出错;
  2. 在调用接口函数时,接口函数会设置errno,我们可以通过errno,strerror(errno)来拿到错误码和错误信息。
  3. 在自定义函数中,我们设置函数错误信息处理的时候,还会采用返回值来处理,这就需要我们来定义一堆的枚举变量来对应不同返回值的错误信息代表;
  4. 在函数嵌套调用的时候,内层函数出现了问题,就需要外层函数不断通过返回值判断,来查看内层函数是否调用出错,直到在某一个外层函数可以处理错误信息时停止;

二、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 = 10
    n = n / 1
    print('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 = 10
    n = n / 0


def fun2():
    fun1()


def main():
    fun2()


main()

        在Python中可以使用logging模块,在捕获异常中使用,来将Python解释器原本打印在显示器上的错误信息记录到logging中,捕获到异常后,将错误信息与异常一并输出,继续向后执行,最后正常退出

import logging


def fun1():
    n = 10
    n = n / 0


def fun2():
    fun1()


def main():
    fun2()


try:
    main()
except Exception as e:
    logging.exception(e)
print('END')

3. logging与print在显示器打印的顺序不同的问题

        在测试时,print 输出和 logging 模块的输出顺序可能不同,原因主要在于它们的缓冲机制和输出流的处理方式。print 函数通常会将输出内容放入缓冲区,等到缓冲区满或者遇到特定条件(如换行符)时,才会将内容真正输出到控制台或终端。而 logging 模块在默认情况下会立即将日志信息输出。

import logging


def fun1():
    n = 10
    n = n / 0


a = 1
try:
    a = 2
    fun1()
except Exception as e:
    logging.exception(e)
print('END a =', a)

        这里想说的就是,不要认为是程序执行顺序的问题,代码中a很好的验证了,程序永远都是自顶向下执行的

4. 主动抛出异常raise

        在Python中所有的异常类型都是一个个的类,所有我们也可以通过继承的方式来自定义一个异常类型,再使用raise来主动抛出异常。

        但自定义异常类型只在必需时使用,其它情况建议使用内置的异常类型即可

class FooError(ValueError):
    pass


def foo(s):
    n = int(s)
    if n == 0:
        raise FooError('value is zero')
    return 10 / n


foo('0')

5. 异常的重新抛出

        主要用于一些函数内部有文件资源的使用、网络连接的使用、数据库资源的使用,不对异常做处理,而是关闭这些资源,再将异常重新抛出给外层,让外层对异常做处理

def foo(s):
    n = int(s)
    if n == 0:
        raise ZeroDivisionError('此时n为0,是不被允许的')
    return 10 / n


def bar():
    try:
        foo('0')
    except ZeroDivisionError as e:
        print('except ValueError')
        raise


try:
    bar()
except ZeroDivisionError as e:
    print('真正处理: ', e)

  • 22
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

终将向阳而生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值