zoukankan      html  css  js  c++  java
  • 五种异常处理机制:try...except与try...finally

    https://www.jb51.net/article/85627.htm

     https://www.jb51.net/article/60638.htm

    http://c.biancheng.net/view/vip_7103.html

    (try finally)

    https://baijiahao.baidu.com/s?id=1636646977338815546&wfr=spider&for=pc   

    http://www.360doc.com/content/19/0703/20/54508727_846532231.shtml   

    https://www.cnblogs.com/windlazio/archive/2013/01/24/2874417.html

    Python try except异常处理详解

    python标准异常

    异常名称描述
    BaseException 所有异常的基类
    SystemExit 解释器请求退出
    KeyboardInterrupt 用户中断执行(通常是输入^C)
    Exception 常规错误的基类
    StopIteration 迭代器没有更多的值
    GeneratorExit 生成器(generator)发生异常来通知退出
    SystemExit Python 解释器请求退出
    StandardError 所有的内建标准异常的基类
    ArithmeticError 所有数值计算错误的基类
    FloatingPointError 浮点计算错误
    OverflowError 数值运算超出最大限制
    ZeroDivisionError 除(或取模)零 (所有数据类型)
    AssertionError 断言语句失败
    AttributeError 对象没有这个属性
    EOFError 没有内建输入,到达EOF 标记
    EnvironmentError 操作系统错误的基类
    IOError 输入/输出操作失败
    OSError 操作系统错误
    WindowsError 系统调用失败
    ImportError 导入模块/对象失败
    KeyboardInterrupt 用户中断执行(通常是输入^C)
    LookupError 无效数据查询的基类
    IndexError 序列中没有没有此索引(index)
    KeyError 映射中没有这个键
    MemoryError 内存溢出错误(对于Python 解释器不是致命的)
    NameError 未声明/初始化对象 (没有属性)
    UnboundLocalError 访问未初始化的本地变量
    ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
    RuntimeError 一般的运行时错误
    NotImplementedError 尚未实现的方法
    SyntaxError Python 语法错误
    IndentationError 缩进错误
    TabError Tab 和空格混用
    SystemError 一般的解释器系统错误
    TypeError 对类型无效的操作
    ValueError 传入无效的参数
    UnicodeError Unicode 相关的错误
    UnicodeDecodeError Unicode 解码时的错误
    UnicodeEncodeError Unicode 编码时错误
    UnicodeTranslateError Unicode 转换时错误
    Warning 警告的基类
    DeprecationWarning 关于被弃用的特征的警告
    FutureWarning 关于构造将来语义会有改变的警告
    OverflowWarning 旧的关于自动提升为长整型(long)的警告
    PendingDeprecationWarning 关于特性将会被废弃的警告
    RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
    SyntaxWarning 可疑的语法的警告
    UserWarning 用户代码生成的警告

    什么是异常?

    异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。 

    一般情况下,在Python无法正常处理程序时就会发生一个异常。

    异常是Python对象,表示一个错误。

    当Python脚本发生异常时我们需要捕获处理它,否则程序会终止执行

    什么是异常处理?

    捕捉异常可以使用try/except语句。

    try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。

    如果你不想在异常发生时结束你的程序,只需在try里捕获它。

    当执行可能出错的代码时,需要适当的异常处理程序用于阻止潜在的错误发生。在异常可能发生的地方添加异常处理程序,对于用户明确错误时一种好方法。即使不能例可解决问题,但是可以记录运行环境并且停止程序运行。在你不能提供自己的异常捕获代码时,python会输出错误消息和关于错误发生处的消息,再停止程序

    >>> short_list=[1,2,3]
    >>> position=5
    >>> short_list[position]
    Traceback (most recent call last):
      File "<pyshell#2>", line 1, in <module>
        short_list[position]
    IndexError: list index out of range
    >>> 

    Python 中,用try except else语句块捕获并处理异常,其基本语法结构如下所示:

    try:
        可能产生异常的代码块
    except [ (Error1, Error2, ... ) [as e] ]:
        处理异常的代码块1
    except [ (Error3, Error4, ... ) [as e] ]:
        处理异常的代码块2
    except  [Exception]:
        处理其它异常
    else:
        未发生异常

    该格式中,[] 括起来的部分可以使用,也可以省略。其中各部分的含义如下:

    • (Error1, Error2,...) 、(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具体的异常类型。显然,一个 except 块可以同时处理多种异常。
    • [as e]:作为可选参数,表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型(后续会用到)。
    • [Exception]:作为可选参数,可以代指程序可能发生的所有异常情况,其通常用在最后一个 except 块。

    try except else的基本语法格式可以看出,try 块有且仅有一个,但 except 代码块可以有多个,且每个 except 块都可以同时处理多种异常。

    当程序发生不同的意外情况时,会对应特定的异常类型,Python 解释器会根据该异常类型选择对应的 except 块来处理该异常。

    try except else 语句的执行流程如下:

    1. 首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常
    2. 当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果在try后的语句里发生了异常,却没有匹配的except子句,异常将被递交到上层的try,或者到程序的最上层(这样将结束程序,并打印缺省的出错信息)
    3. 如果在try子句执行时没有发生异常,python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句


    事实上,不管程序代码块是否处于 try 块中,甚至包括 except 块中的代码,只要执行该代码块时出现了异常,系统都会自动生成对应类型的异常。但是,如果此段程序没有用 try 包裹,又或者没有为该异常配置处理它的 except 块,则 Python 解释器将无法处理,程序就会停止运行;反之,如果程序发生的异常经 try 捕获并由 except 处理完成,则程序可以继续执行。

    示例(1):代码运行正常

    try:
        a = int(input("输入被除数:"))
        b = int(input("输入除数:"))
        c = a / b
        print("您输入的两个数相除的结果是:", c )
    except (ValueError, ArithmeticError):
        print("程序发生了数字格式异常、算术异常之一")
    except :
        print("未知异常")
    else:
        print("未发生异常")
    print("程序继续运行")
            

    运行结果:

    输入被除数:9
    输入除数:3
    您输入的两个数相除的结果是: 3.0
    未发生异常
    程序继续运行

    示例(2)代码运行失败

    输入被除数:a
    程序发生了数字格式异常、算术异常之一
    程序继续运行
    >>> 

    上面程序中,第 6 行代码使用了(ValueError, ArithmeticError)来指定所捕获的异常类型,这就表明该 except 块可以同时捕获这 2 种类型的异常;第 8 行代码只有 except 关键字,并未指定具体要捕获的异常类型,这种省略异常类的 except 语句也是合法的,它表示可捕获所有类型的异常,一般会作为异常捕获的最后一个 except 块,但这不是一个很好的方式,我们不能通过该程序识别出具体的异常信息

    除此之外,由于 try 块中引发了异常,并被 except 块成功捕获,因此程序才可以继续执行,才有了“程序继续运行”的输出结果。

    获取特定异常的有关信息

    通过前面的学习,我们已经可以捕获程序中可能发生的异常,并对其进行处理。但是,由于一个 except 可以同时处理多个异常,那么我们如何知道当前处理的到底是哪种异常呢?

    其实,每种异常类型都提供了如下几个属性和方法,通过调用它们,就可以获取当前处理异常类型的相关信息:

         1)args:返回异常的错误编号和描述字符串;

          2)str(e):返回异常信息,但不包括异常信息的类型;

          3)repr(e):返回较全的异常信息,包括异常信息的类型

    try:
        1/0
    except Exception as e:
        # 访问异常的错误编号和详细信息
        print(e.args)
        print(str(e))
        print(repr(e))

    输出结果为:

    ('division by zero',)
    division by zero
    ZeroDivisionError('division by zero',)
    除此之外,如果想要更加详细的异常信息,可以使用 traceback 模块。有兴趣的读者,可自行查阅资料学习

    从程序中可以看到,由于 except 可能接收多种异常,因此为了操作方便,可以直接给每一个进入到此 except 块的异常,起一个统一的别名 e。

    python中的try/except/else/finally语句

    与其他语言相同,在python中,try/except语句主要是用于处理程序正常执行过程中出现的一些异常情况,如语法错误(python作为脚本语言没有编译的环节,在执行过程中对语法进行检测,出错后发出异常消息)、数据除零错误、从未定义的变量上取值等;

    Python 异常处理机制还提供了一个 finally 语句,通常用来为 try 块中的程序做扫尾清理工作。如在通信过程中,无论通信是否发生错误,都需要在通信完成或者发生错误时关闭网络连接。

    注意,和 else 语句不同,finally 只要求和 try 搭配使用,而至于该结构中是否包含 except 以及 else,对于 finally 不是必须的(else 必须和 try except 搭配使用)。

     在整个异常处理机制中,finally 语句的功能是:无论 try 块是否发生异常,最终都要进入 finally 语句,并执行其中的代码块。

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

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

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

    默认情况下,在程序段的执行过程中,如果没有提供try/except的处理,脚本文件执行过程中所产生的异常消息会自动发送给程序调用端,如python shell,而python shell对异常消息的默认处理则是终止程序的执行并打印具体的出错信息。这也是在python shell中执行程序错误后所出现的出错打印信息的由来。尽管try/except和try/finally的作用不同,但是在编程实践中通常可以把它们组合在一起使用try/except/else/finally的形式来实现稳定性和灵活性更好的设计。
     
    python中try/except/else/finally语句的完整格式如下所示:
    try:
         Normal execution block
    except A:
         Exception A handle
    except B:
         Exception B handle
    except:
         Other exception handle
    else:
         if no exception,get here
    finally:
         print("finally")   
    说明:
    正常执行的程序在try下面的Normal execution block执行块中执行,在执行过程中如果发生了异常,则中断当前在Normal execution block中的执行跳转到对应的异常处理块中开始执行;
    python从第一个except X处开始查找,如果找到了对应的exception类型则进入其提供的exception handle中进行处理,如果没有找到则直接进入except块处进行处理。except块是可选项,如果没有提供,该exception将会被提交给python进行默认处理,处理方式则是终止应用程序并打印提示信息;
    如果在Normal execution block执行块中执行过程中没有发生任何异常,则在执行完Normal execution block后会进入else执行块中(如果存在的话)执行。
    无论是否发生了异常,只要提供了finally语句,以上try/except/else/finally代码块执行的最后一步总是执行finally所对应的代码块。
    需要注意的是:
    1.在上面所示的完整语句中try/except/else/finally所出现的顺序必须是try-->except X-->except-->else-->finally,即所有的except必须在else和finally之前,else(如果有的话)必须在finally之前,而except X必须在except之前。否则会出现语法错误。
    2.对于上面所展示的try/except完整格式而言,else和finally都是可选的,而不是必须的,但是如果存在的话else必须在finally之前,finally(如果存在的话)必须在整个语句的最后位置。
    3.在上面的完整语句中,else语句的存在必须以except X或者except语句为前提,如果在没有except语句的try block中使用else语句会引发语法错误。也就是说else不能与try/finally配合使用。
    4.except的使用要非常小心,慎用。
    class AError(Exception):
         """AError---exception"""
         print('AError')
     
    try:
         #raise AError
         asdas('123')
    except AError:
         print("Get AError")
    except:
         print("exception")     
    else:
         print("else")
    finally:
         print("finally")     
    print("hello wolrd")
    在上面的代码中,Normal execution block中出现了语法错误,但是由于使用了except语句,该语法错误就被掩盖掉了。因此在使用try/except是最好还是要非常清楚的知道Normal execution block中有可能出现的异常类型以进行针对性的处理。
     
    try:
        a = int(input("请输入 a 的值:"))
        print(20/a)
    except:
        print("发生异常!")
    else:
        print("执行 else 块中的代码")   
    finally :
        print("执行 finally 块中的代码")

    运行此程序:

    请输入 a 的值:4
    5.0
    执行 else 块中的代码
    执行 finally 块中的代码

    可以看到,当 try 块中代码为发生异常时,except 块不会执行,else 块和 finally 块中的代码会被执行。

    再次运行程序:

    请输入 a 的值:a
    发生异常!
    执行 finally 块中的代码

    可以看到,当 try 块中代码发生异常时,except 块得到执行,而 else 块中的代码将不执行,finally 块中的代码仍然会被执行。

    finally 块的强大还远不止此,即便当 try 块发生异常,且没有合适和 except 处理异常时,finally 块中的代码也会得到执行。例

    try:
        #发生异常
        print(20/0)
    finally :
        print("执行 finally 块中的代码")

    程序执行结果为:

    执行 finally 块中的代码
    Traceback (most recent call last):
      File "D:python3.61.py", line 3, in <module>
        print(20/0)
    ZeroDivisionError: division by zero

    可以看到,当 try 块中代码发生异常,导致程序崩溃时,在崩溃前 Python 解释器也会执行 finally 块中的代码。

    Python中关于try...finally的一些疑问

    以“Open-Read-Write"文件为例,执行操作中,当某流程执行失败时,都要先Close文件后再返回相关内容。如果操作流程多,每个步骤都要写上close函数,这样会出现漏写的情况

          

    以try-except-else-finally。的好处是避免了频繁写close函数、

    先以代码引入

    def func(x):
        try:
            return ++x
        finally:
            return x+1

    func(11)
    你觉得是几?

    看到问题,觉得肯定是12啊

    下边看看我写的例子,就明白其中的问题了。

    示例1

    def f():
        try:
            print(1)
            return 1
        finally:
            print(0)
            return 0

    f()
    结果为 1 0 0
    以运行结果为准,说明无论try里执行什么,即使是return,也会调用finally的。
    但是有一个问题,为什么最后输出的不是1而是0呢?明明try里面已经返回1了!

    def f():
        try:
            print(1)
            return 1
        finally:
            print(0)
            #return 0

    将finally的return屏蔽掉,你或许猜到结果了

    结果为 1 0 1

    诧异吗?

    对比上个结果,说明try的返回值被finally的返回值覆盖了,或许是因为一个函数只能有一个返回值,以最后一个结果为准

    由此我想再验证下else的情况,如下:

    def f():
        try:
            print(1)
            return 1
        except:
            return 2
        else:
            print(3)
            return 3
        finally:
            print(0)
            #return 0

    你觉得,没有异常else会执行吗?

    如你所料,并没有执行。

    结果为 1 0 1

    说明try里面运行完之后return,阻挡了else的执行,但是并没有影响finally的执行。

    借用Vamer文章的两句话:

    “如果try中没有异常,那么except部分将跳过,执行else中的语句。

    finally是无论是否有异常,最后都要做的一些事情。”

    这里补充一句,在含有return的情况下,并不会阻碍finally的执行。

  • 相关阅读:
    添加组合索引时,做相等运算字段应该放在最前面
    常用位运算
    redis php扩展简单使用
    mysql优化之简单概念
    mysql优化之sql语句优化
    简单画图 gd库函数
    win下 安装mongodb
    伪静态之实际应用
    tomcat win简单配置
    docker
  • 原文地址:https://www.cnblogs.com/bashliuhe/p/12600009.html
Copyright © 2011-2022 走看看