首页 > 编程语言 >Python系列(9)- Python 异常处理机制

Python系列(9)- Python 异常处理机制

时间:2024-08-26 12:25:36浏览次数:7  
标签:Exception 系列 raise Python except try print 机制 异常


1. 错误和异常

    编程开发时一般会遇到 2 种类型的错误,分别为语法错误和运行时错误。

    语法错误 (Syntax Error): Python 解释器在解析代码时遇到的错误,比如拼写错误、不符合语法规则等。Python 解释器会提示错误的类型和出错的位置,便于开发者及时纠正错误,在错误没有得到纠正之前,代码无法被正常执行。

    运行时错误(Runtime Error): 程序代码在语法上都是正确的,但在运行时发生了错误。在 Python 中,把这种运行时产生错误的情况叫做异常 (Exception)。

    Python 常见的 Exception 子类异常:

        异常类型                描述
        AssertionError        当 assert 关键字后的条件为假时,程序运行会停止并抛出 AssertionError 异常
        AttributeError        当试图访问的对象属性不存在时抛出的异常
        IndexError            索引超出序列范围会引发此异常
        KeyError            字典中查找一个不存在的关键字时引发此异常
        MemoryError         内存溢出错误
        NameError            尝试访问一个未声明的变量时,引发此异常
        OSError             操作系统错误
        RuntimeError        一般的运行时错误
        SyntaxError         Python 语法错误
        StopInteration      迭代器没有更多值
        TypeError            不同类型数据之间的无效操作
        ValueError          传入无效的参数
        ZeroDivisionError    除法运算中除数为 0 引发此异常

 

2. 异常处理

    1) try ... except 语句

        Python 异常处理机制提供了 try ... except 语句捕获并处理异常,语法格式如下:

            try:
                代码块
            except [(Error1, Error2, ... ) [as e]]:
                异常处理代码块
            except [Exception [as e]]:
                默认异常处理

        解释说明:
            
            (1) try: try 语句到第一个 except 之间称为 try 块,用来监控执行时可能会发生异常的代码;
            (2) except [(Error1, Error2, ... ) [as e]]: 一个 except 块可以捕获多种异常类型(Error1, Error2, ...),[as e] 给异常类型取个别名 e;
            (3) except [Exception [as e]]: except 语句捕获异常信息,无法判断异常类型,调用默认异常处理;

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            try:
                a = 'text'
                b = 0
                c = a / b
                print("c:", c)
            except (NameError, ZeroDivisionError) as e:
                print(repr(e))
            except Exception as e:
                print(repr(e))

        输出结果如下:

            TypeError("unsupported operand type(s) for /: 'str' and 'int'")

        注:a 是 str 类型,a 不能进行算术运算。如果把 a = 'text' 这行去掉或注释掉,输出结果如下:

                NameError("name 'a' is not defined")

            如果修改 a = 1,输出结果如下:

                ZeroDivisionError('division by zero')

            repr(e) 函数可以返回异常对象的类型信息,e.args

    2) try ... except else 语句

        Python 异常处理机制还提供了一个 else 语句,在 try except 语句的基础上添加一个 else 语句,语法格式如下:

            try:
                代码块
            except [(Error1, Error2, ... ) [as e]]:
                异常处理代码块
            except [Exception [as e]]:
                默认异常处理
            else:
                没有异常处理

        当 try 块没有捕获到任何异常时,else 语句才会被执行;如果 try 块捕获到异常,调用对应的 except 语句处理异常,else 语句不会被执行。

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            try:
                a = 1
                b = 2
                c = a / b
                print("c:", c)
            except (NameError, ZeroDivisionError) as e:
                print(repr(e))
            except Exception as e:
                print(repr(e))
            else:
                print('No exception')    

        输出结果如下:

            c: 0.5
            No exception                

    3) try ... except finally 语句

        Python 内存回收机制,能帮我们回收变量、类对象占用的内存,而无法自动完成类似关闭文件、数据库连接等工作。

        Python 异常处理机制还提供了一个 finally 语句,用来为 try 块的代码做清理工作(比如:关闭文件句柄、数据库连接等),语法格式如下:

            try:
                代码块
            except [(Error1, Error2, ... ) [as e]]:
                异常处理代码块
            except [Exception [as e]]:
                默认异常处理
            [else:]
                [没有异常处理]
            finally:
                清理工作

            注:[] 括表示非必选项。

        无论 try 块是否发生异常,是否包含 else 语句,最终都会进入 finally 语句。

        基于 finally 语句的这种特性,在某些情况下,当 try 块中的程序打开了一些物理资源(文件、数据库连接等)时,由于这些资源必须手动回收,而回收工作通常就放在 finally 块中。

        必须使用 finally 块吗?当然不是,但使用 finally 块是比较好的选择。首先,try 块不适合做资源回收工作,因为一旦 try 块中的某行代码发生异常,则其后续的代码将不会得到执行;其次 except 和 else 也不适合,它们都可能不会得到执行。而 finally 块中的代码,无论 try 块是否发生异常,该块中的代码都会被执行。

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            try:
                a = 1
                b = 2
                c = a / b
                print("c:", c)
            except (NameError, ZeroDivisionError) as e:
                print(repr(e))
            except Exception as e:
                print(repr(e))
            #else:
            #    print('No exception')                    
            finally:
                print('finally')

        输出结果如下:

            c: 0.5
            finally

    4) raise 语句

        Python 异常处理机制提供了手动抛出异常的 raise 语句,语法格式如下:

            raise [exceptionName [(reason)]]

        解释说明:

            (1) raise:raise 后不带参数,引发当前上下文中捕获的异常(也可以在 except 块中),或默认引发 RuntimeError 异常;
            (2) raise 异常类名称:raise 后带一个异常类名称,表示引发执行类型的异常;
            (3) raise 异常类名称(描述信息):在引发指定类型的异常的同时,附带异常的描述信息;

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            try:
                a = 'text'
                b = 2

                if type(a) != int:
                    raise

                c = a / b
                print("c:", c)
            except Exception as e:
                print(repr(e))

        输出结果如下:

            RuntimeError('No active exception to reraise')

        注:a 是 str 类型,a 不能进行算术运算。在程序运行到 c = a / b 语句之前,我们提前判断 a 的类型,如果 a 不是整型,运行不带参数的 raise (引发一个 RuntimeError 异常)。

            如果把不带参数的 raise 改成 raise TypeError('\'a\' must be an integer'),输出结果如下:

                TypeError("'a' must be an integer")

            Exception 类是 TypeError 类的基类, e 是个基类变量,子类赋值给基类变量,会表现出多态。

 

3. 获取更详细异常信息

    有 2 种方式可以更详细异常信息,分别是:

        (1) 使用 sys 模块中的 exc_info 方法;
        (2) 使用 traceback 模块中的相关函数。

    1) sys.exc_info() 方法

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            import sys

            try:
                a = 1
                b = 0
                c = a / b
                print("c:", c)
            except Exception as e:
                print(repr(e))
                print(sys.exc_info())

        输出结果如下:

            ZeroDivisionError('division by zero')
            (<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x000001C77C19EB00>)

    2) traceback 模块

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-

            import traceback

            def func():
                func2()

            def func2():
                func3()

            def func3():
                raise Exception('Unknown error')

            try:
                func()
            except Exception as e:
                traceback.print_exc()
                #traceback.print_exc(file=open('log.txt', 'a'))

        输出结果如下:

            Traceback (most recent call last):
            File "d:/pythonDemo/except2.py", line 16, in <module>
                func()
            File "d:/pythonDemo/except2.py", line 7, in func
                func2()
            File "d:/pythonDemo/except2.py", line 10, in func2
                func3()
            File "d:/pythonDemo/except2.py", line 13, in func3
                raise Exception('Unknown error')
            Exception: Unknown error

        注:traceback.print_exc() 方法可以生成一个包含异常详细信息的 log.txt 文件。


4. 自定义异常类

    Python 中自定义异常类,可以通过继承内置的 Exception 类或其子类来实现。自定义异常类可以让我们更精确地描述和处理特定的错误情况。

    示例:

        #!/usr/bin/python3
        # -*- coding: UTF-8 -*-

            class CustomError(Exception):
                def __init__(self, message):
                    super().__init__(message)

                def __str__(self):
                    return super().__str__()

            try:
                a = 1
                b = 0

                if b == 0:
                    raise CustomError('division by zero')

                c = a / b
                print("c:", c)
            except Exception as e:
                print(e)
                print(repr(e))
                print(e.args)

    输出结果如下:

        division by zero
        CustomError('division by zero')
        ('division by zero',)

    自定义的 CustomError 异常类,实现了内置的异常类 ZeroDivisionError 的功能。把判断 b == 0 行和 raise 行注释掉,输出结果如下:

        division by zero
        ZeroDivisionError('division by zero')
        ('division by zero',)


5. 异常链(Exception Chaining)

    在Python中,异常链接(Exception Chaining)是指在处理一个异常时抛出另一个异常的技术。这样可以保留原始异常的信息,同时提供新的异常信息。这种机制在调试和错误跟踪时特别有用,因为它保留了异常发生的完整上下文。

    Python 通过两个属性来支持异常链接:显式链 (__cause__) 和隐式链 (__context__)。

    1) 显式链 (__cause__)

        用于显示一个异常是由另一个异常引发的。通过 raise new_exception from original_exception 语法来使用。

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-
            
            try:

                try:
                    1 / 0
                except ZeroDivisionError as e:
                    raise ValueError('Exception Chaining error') from e
                
            except Exception as e2:
                print(repr(e2))
                print(repr(e2.__cause__))

        输出结果如下:

            ValueError('Exception Chaining error')
            ZeroDivisionError('division by zero')

    2) 隐式链 (__context__)

        用于记录在处理一个异常的过程中发生的另一个异常。这在没有使用 from 语句时自动设置。

        示例:

            #!/usr/bin/python3
            # -*- coding: UTF-8 -*-
            
            try:

                try:
                    1 / 0
                except ZeroDivisionError as e:
                    raise ValueError('Exception Chaining error')
                
            except Exception as e2:
                print(repr(e2))
                print(repr(e2.__context__))

        输出结果如下:

            ValueError('Exception Chaining error')
            ZeroDivisionError('division by zero')


标签:Exception,系列,raise,Python,except,try,print,机制,异常
From: https://www.cnblogs.com/tkuang/p/18380800

相关文章

  • MacOS安装 Python 和 PyCharm
    MacOS安装Python3.12.5和PyCharm小阿呜有话说一、MacOS安装PythonPython官网下载二、MacOS安装PyCharmPyCharm官网下载叮嘟!这里是小啊呜的学习课程资料整理。好记性不如烂笔头,今天也是努力进步的一天。一起加油进阶吧!小阿呜有话说前不久换了新电脑,需要重新......
  • Python批量发送邮件如何实现邮件群发策略?
    Python批量发送邮件怎么定制化?如何使用Python发信?Python批量发送邮件已经成为一种不可或缺的工具。Python批量发送邮件都能大大提高效率,节省时间和资源。AokSend将详细介绍如何利用Python批量发送邮件实现高效的邮件群发策略。Python批量发送邮件:设置环境要开始Python批量......
  • Python画笔案例-012 绘制空心T字
    1、绘制空心T字通过python的turtle库绘制一个空心T字的图案,如下图:2、实现代码 绘制以上空心T字的图案,代码如下:"""空心T字.py"""importturtle#导入海龟模块turtle.pensize(2)#设定海龟画笔粗细为2turtle.setheading(90)......
  • Python画笔案例-013 绘制水墨风格画
    1、绘制水墨风格画通过python的turtle库绘制一个水墨风格画的图案,如下图:2、实现代码 绘制以上水墨风格画图案,代码如下:"""水墨风格画.py"""importturtle#导入海龟模块turtle.penup()#抬笔turtle.goto(-200,-200)#坐......
  • 利用python连接MySQL数据库
    利用python连接MySQL数据库1、准备工作:(1)事先在系统中已经安装好mysql数据库(2)在系统控制台通过pipinstallpymysql,安装python的第三方数据库模块2、利用python连接数据库#导入模块importpymysql#连接数据库conn=pymysql.connect(host="127.0.0.1",user="root",pas......
  • Python time时间格式化
    1、时间戳转换为指定格式日期importtimet=time.strftime("%Y-%m-%d%H:%M:%S",time.localtime())print(t)timestamp=time.time()tuple_time=time.localtime(timestamp)print(tuple_time)print(time.strftime("%Y-%m-%d%H:%M:%S",tuple_time)) ......
  • VaR(风险价值模型)的Python实现案例
    VaR(ValueatRisk)即风险价值模型,是一种衡量市场风险的统计指标,用于估计在一定置信水平下,某一金融资产或证券组合在给定时间内可能遭受的最大损失。VaR的提出背景是为了解决传统资产负债管理方法的时效性不足和无法准确度量金融衍生品种的风险等问题例如,如果VaR是-5%,这意味着在......
  • [oeasy]python031_[趣味拓展]unix起源_Ken_Tompson_Ritchie_multics
    [趣味拓展]unix起源_Ken_Tompson_Ritchie_multics......
  • 隐私指纹浏览器产品系列 —— 浏览器指纹 中(三)
    1.引言在上一篇文章中,我们聊到了最老牌的浏览器指纹检测站——BrowserLeaks。BrowserLeaks曾经是浏览器指纹检测的权威,但它似乎更像是一本老旧的工具书,只能呆板告诉你浏览器的指纹值,并对比不同浏览器的指纹差异。今天,我们来聊一下指纹检测站的新星——CreepJS。与前辈相比,Cre......
  • ROS机器人入门系列(二)实现HelloWorld(c++/python)
    一、实现流程1、创建工作空间2、创建功能包3、编辑源文件4、编辑配置文件5、编译并执行其中,c++和python的差异仅体现在3,4两部,其他流程基本一致。二、创建工作空间和创建功能包的实现2.1 创建工作空间并初始化(1)创建工作空间mkdir-p自定义工作空间名称/src这里......