• Python教学课程分享10-异常处理结构


    10.1  异常概念与常见表现形式

    异常是一个事件,这个事件会在程序执行过程中发生,影响程序的正常进行。一般情况下,在Python无法正常进行程序时就会发生异常。异常是Python的对象,它表示一个错误,在Python脚本在发生异常时,需要对异常进行捕获及处理,否则程序会被终止执行。

    每个异常都是一些类的实例,这些实例可以被引用,并且可以用很多种方法进行捕捉,使得这些错误可以被处理,而不是让整个进程失败。

    需要注意的是,异常和错误的概念并不相同。异常一般是指运行时由于某些条件不符合而引发的错误,一但引发异常并且没有得到有效的处理,一般是直接导致程序崩溃。错误又可以分为语法错误和逻辑错误两种。拼写错误、缩进不一致、引号或括号不闭合等问题都属于语法错误,一般来说,存在语法错误的代码是无法运行的,这类错误很容易发现和解决;而存在逻辑错误代码则通常可以运行,但是非常可能会得到一个错误的结果,这类错误非常难发现。

    常见的异常表现形式有以下几种,如下表10.1

    10.1  Python常见标准异常表

    表现形式

    功能

    SystemExit

    解释器请求退出

    Warning

    警告的基类

    RuntimeError

    一般的运行时错误

    KeyError

    映射中没有这个键

    SystemError

    一般的解释器系统错误

    AttributeError

    对象没有这个属性

    IndexError

    序列中没有此索引

    MemoryError

    内存溢出错误(对于Python解释器不是致命的)

    WindowsError

    系统调用失败

    IOError

    输入/输出操作失败

    OverflowError

    树枝运算超出最大限制

    UserWarning

    用户代码生成的警告

    10.2  常见异常处理结构

    当编程人员在执行代码时,有些代码可能会出现错误,也有可能不会出现错误,这主要由运行时的各种客观因素来决定,此时建议使用异常处理结构。如果使用大量的选择结构来提前进行判断,仅当满足相应的条件时才执行该代码,这些条件判断可能会严重干扰正常的业务逻辑,也会严重降低代码的可读性,所以需要使用异常处理结构来保证业务逻辑的正常运行。Python提供了多种不同形式的异常处理结构,它们的基本思路都是一致的;先尝试运行代码,然后处理可能发生的错误。在实际使用时,可以根据需要来选择使用哪一种。

    10.2.1  try...except...

    Python异常处理结构中最基本的结构是结构。其中try子句中的代码块包含着可能会引发异常的语句,而except子句则用来捕捉相应的异常。如果try子句中的代码引发异常并被except子句捕捉,则执行except子句的代码块;如果try子句中的代码块没有出现异常,则继续往下执行异常处理结构之后的代码;如果出现异常但没有被except捕获,则继续往外层抛出;如果所有层都没有捕获并处理该异常,则程序崩溃并将该异常呈现给最终用户,而这是编程者最不希望发生的事情。该结构语法如下:

    try

    #可能会引发异常的代码,先执行一下试试

    except Exception[ as reason]:

    #如果try中的代码抛出异常并被except捕捉,就执行这里的代码

     

    该结构的示例代码如下:

    #!/usr/bin/env python

    # -*- coding: UTF-8 -*-

    def exp_exception(x,y):

    try:

    a = x/y

    print('a=',a)

    return a

    except Exception:

    print('程序出现异常,异常信息:被除数为0')

     

    exp_exception(2,0)

     

    上方代码执行后输出结果如下:

    程序出现异常,异常信息:被除数为0

     

    由执行结果可见,程序最后执行的是except子句,如果语句未出现异常,则应该输出”a=”的形式。

    在此段代码中,也可以直接在做除法前对y值进行判断来解决问题,也可以解决问题,但是如果给程序程序加入更多除法,就得给每个除法语句上都加一个判断语句,这样整个代码看上去就是一堆类似if的功能重复判断语句,真正有效的代码没有多少。而使用try/except语句结构只需要一个错误处理器即可,省时省力。

     

    10.2.2  try...except...else...

    带有else子句的异常处理结构可以看做是一种特殊的选择结构,如果try子句中的代码抛出了异常并且被某个except语句捕捉则执行相应的异常处理代码,这种情况下就不会执行else中的代码;如果try子句中的代码没有抛出异常,则执行else子句中的代码块。该结构的语法如下:

    try

    #可能会引发异常的代码块

    except Exception [ as reason]

    #用来处理异常的代码

    else:

    #如果try子句中的代码没有引发异常,就继续执行这里的代码

    用该结构来要求用户必须输入整数,该结构的示例代码如下:

    >>> while True

    x = input('Please input:')

    try:

    x = int(x)

    except Exception as e:

    print('Error.')

    else:

    print('You have input {0}'.format(x))

    break

    Please input:a

    Error.

    Please input:b

    Error.

    Please input:888c

    Error.

    Please input:888

    You have input 888

     

    10.2.3  带多个except的异常处理结构

    在实际开发中,同一段代码可能会抛出多种异常,并且需要针对不同的异常类型对代码进行相应的处理。为了支持多种异常的捕获和处理,Python提供了带有多个except的异常处理结构,一但某个except子句捕捉到了异常,则其它的except子句将不会再尝试捕捉异常。该结构类似于多分支选择结构,它的语法格式为:

    >>> try:

    x = float(input('请输入被除数:'))

    y = float(input('请输入除数:'))

    z = float(x)/y

    except ZeroDivisionError:

    print('除数不能为零')

    except TypeError:

    print('被除数和除数应为数值类型')

    except NameError:

    print('变量不存在')

    else:

    print(x,'/',y,'=',z)

     

    请输入被除数:30 #第一次运行

    请输入除数:5

    30.0 / 5.0=6.0

     

    请输入被除数:30 #第二次运行,略去重复代码

    请输入除数:abc

    Traceback(most recent call last):

    File”<pyshell#95>”,line 3,in<moudle>

    y = float(input('请输入除数:'))

    ValueError:could not convert string to float:'abc'

     

    请输入被除数:30 #第三次运行,略去重复代码

    请输入除数:0

    除数不能为零

     

    在实际开发中,有时候可能会为几种不同的异常设计相同的处理代码。为了减少代码量,Python允许将多个异常类型放到同一个元组中,然后使用一个except子句同时进行捕捉多种异常,并且共用同一段异常处理代码,例如:

    >>> try:

    x = float(input('请输入被除数:'))

    y = float(input('请输入除数:'))

    z = float(x)/y

    except(ZeroDivisionError,TypeError,NameError):

    print('捕捉到了异常')

    else:

    print(x,'/',y,'=',z)

     

    请输入被除数:30

    请输入除数:0

    捕捉到了异常

     

    10.2.4  try...finally...

    在此结构中,无论try中的代码是否会发生异常,也不管抛出的异常有没有被except语句捕捉到,finally子句中的代码总会得到执行。因此,finally语句中的代码常用来做一些清理工作以释放try子句中申请的资源。

    如果try子句中的异常没有被except捕获和处理,或者except子句或else子句中的代码抛出了异常,那么这些异常将会在finally子句执行完毕后再次抛出。

    如果在函数中使用异常处理结构,尽量不要在finally子句中使用return语句,以免发生非常难以发现的逻辑错误。该语法结构如下:

    try:

    #可能会引发异常的代码

    except Exception [ as reason]:

    #处理异常的代码

    finally:

    #无论try子句中的代码是否引发异常,都会执行此子句中的代码块

     

    finally子句中的代码也有可能会引发异常。例如下面的代码,本意是使用异常处理结构来避免文件对象没有关闭的情况发生,但是由于指定的文件不存在,导致打开文件失败,结果在finally子句中关闭文件时引发了异常。示例代码如下:

    >>> try:

    f1 = open('test1.txt','r') #文件不存在,抛出异常,不会创建文件对象f1

    line = f1.readline() #后面的代码不会被执行

    print(line)

    except SyntaxError: #这个except并不能捕捉上面的异常

    print('Sth wrong')

    finally:

    f1.close() #f1不存在,再次引发异常

     

    Traceback(most recent call last):

    File”<pyshell#75>”,line 2,in<moudle>

    f1 = open('test1.txt','r')

    FileNotFoundError:[Error2]No such file or directory:'test1.txt'

     

    During handling of the above exception,another exception occurred:

    Traceback(most recent call last):

    File”<pyshell#75>”,line 8,in<moudle>

    f1.close()

    NameError:name 'f1'is not defined

    10.3  raise语句

    Python使用raise语句抛出一个指定异常。使用者可以使用类(Exception的子类)或实例参数来调用raise语句引发异常。使用类时程序会自动创建实例。

    >>> raise Exception

    Traceback(most recent call last):

    File”<pyshell#1>”,line 1,in <module>

    raise Exception

    Exception

    >>> raise NameError('This is NameError')

    Traceback(most recent call last):

    File”<pyshell#0>”,line 1,in <module>

    raise NameError('This is NameError')

    NameError:This is NameError

    由操作结果可得,第一个示例raise Exception引发了一个没有相关错误信息的普通异常,第二个示例输出了一些错误提示。

    如果只想知道是否抛出了异常,并不想处理,使用一个简单的raise语句就可以再次把异常抛出,例如:

    >>> try:

    raise NameError('This is NameError')

    except NameError:

    print('An exception happened!')

     

    An exception happened!

     

    >>> try:

    raise NameError('This is NameError')

    except NameError:

    print('An exception happened!')

    raise

     

    An exception happened!

    Traceback(most recent call last):

    File”<pyshell#11>”,line 2,in <module>

    raise NameError('This is NameError')

    NameError:This is NameError

     

    由输出结果可得,使用raise可以输出更深层次的异常。在使用过程中,可以借助该方法得到更详尽的异常信息。

    前面碰到的NameErrorSyntaxErrorTypeErrorValueError等异常类称为内建异常类。在Python中,内建的异常类有很多,可以使用dir函数列出异常类的内容,并用在raise语句中,用法如raise NameError这般。表10.2列出了一些重要的内建异常类。

    10.2 Python重要的内建异常类

    异常名称

    描述

    Exception

    常规错误的基类

    AttributeError

    对象没有这个属性

    IOError

    输入/输出操作失败

    IndexError

    序列中没有此索引

    KeyError

    映射中没有这个键

    NameError

    未声明/初始化对象(没有属性)

    SyntaxError

    Python语法错误

    SystemError

    一般解释器系统错误

    ValueError

    传入无效的参数

  • 相关阅读:
    飞思卡尔单片机CAN模块的物理特性的示波器观察
    飞思卡尔CAN模块关于ID和mask的使用
    基本数据库语句
    深入分析Spring 与 Spring MVC容器
    Linux常用命令大全
    datagrid行内编辑时为datetimebox
    SVN上拖下来的项目,缺少build path怎么办?
    sql中的in与not in,exists与not exists的区别
    Spring中@Component的作用
    浅谈@RequestMapping @ResponseBody 和 @RequestBody 注解的用法与区别
  • 原文地址:https://www.cnblogs.com/yiyi314/p/11187774.html
Copyright © 2020-2023  润新知