1 引言

  在我们调试程序时,经常不可避免地出现意料之外的情况,导致程序不得不停止运行,然后提示大堆提示信息,大多是这种情况都是由异常引起的。异常的出现一方面是因为写代码时粗心导致的语法错误,这种错误在程序编译时就可以发现;另一方面也可能是因为程序逻辑错误,这种错误往往是不可避免地,只能通过异常处理来防止程序退出。

2 异常类型

  Python自带的异常处理机制非常强大,提供了很多内置异常类,可向用户准确反馈出错信息。Python是面向对象语言,认为一切皆对象,所以异常也是对象。Python异常处理机制中的BaseException是所有内置异常的基类,但用户定义的类并不直接继承BaseException,所有的异常类都是从Exception继承,且都在exceptions模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。

  Python内置异常类继承层次结构如下:

BaseException  # 所有异常的基类

 +-- SystemExit  # 解释器请求退出

 +-- KeyboardInterrupt  # 用户中断执行(通常是输入^C)

 +-- GeneratorExit  # 生成器(generator)发生异常来通知退出

 +-- Exception  # 常规异常的基类

      +-- StopIteration  # 迭代器没有更多的值

      +-- StopAsyncIteration  # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代

      +-- ArithmeticError  # 各种算术错误引发的内置异常的基类

      |    +-- FloatingPointError  # 浮点计算错误

      |    +-- OverflowError  # 数值运算结果太大无法表示

      |    +-- ZeroDivisionError  # 除(或取模)零 (所有数据类型)

      +-- AssertionError  # 当assert语句失败时引发

      +-- AttributeError  # 属性引用或赋值失败

      +-- BufferError  # 无法执行与缓冲区相关的操作时引发

      +-- EOFError  # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发

      +-- ImportError  # 导入模块/对象失败

      |    +-- ModuleNotFoundError  # 无法找到模块或在在sys.modules中找到None

      +-- LookupError  # 映射或序列上使用的键或索引无效时引发的异常的基类

      |    +-- IndexError  # 序列中没有此索引(index)

      |    +-- KeyError  # 映射中没有这个键

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

      +-- NameError  # 未声明/初始化对象 (没有属性)

      |    +-- UnboundLocalError  # 访问未初始化的本地变量

      +-- OSError  # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类

      |    +-- BlockingIOError  # 操作将阻塞对象(e.g. socket)设置为非阻塞操作

      |    +-- ChildProcessError  # 在子进程上的操作失败

      |    +-- ConnectionError  # 与连接相关的异常的基类

      |    |    +-- BrokenPipeError  # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入

      |    |    +-- ConnectionAbortedError  # 连接尝试被对等方中止

      |    |    +-- ConnectionRefusedError  # 连接尝试被对等方拒绝

      |    |    +-- ConnectionResetError    # 连接由对等方重置

      |    +-- FileExistsError  # 创建已存在的文件或目录

      |    +-- FileNotFoundError  # 请求不存在的文件或目录

      |    +-- InterruptedError  # 系统调用被输入信号中断

      |    +-- IsADirectoryError  # 在目录上请求文件操作(例如 os.remove())

      |    +-- NotADirectoryError  # 在不是目录的事物上请求目录操作(例如 os.listdir())

      |    +-- PermissionError  # 尝试在没有足够访问权限的情况下运行操作

      |    +-- ProcessLookupError  # 给定进程不存在

      |    +-- TimeoutError  # 系统函数在系统级别超时

      +-- ReferenceError  # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象

      +-- RuntimeError  # 在检测到不属于任何其他类别的错误时触发

      |    +-- NotImplementedError  # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现

      |    +-- RecursionError  # 解释器检测到超出最大递归深度

      +-- SyntaxError  # Python 语法错误

      |    +-- IndentationError  # 缩进错误

      |         +-- TabError  # Tab和空格混用

      +-- SystemError  # 解释器发现内部错误

      +-- TypeError  # 操作或函数应用于不适当类型的对象

      +-- ValueError  # 操作或函数接收到具有正确类型但值不合适的参数

      |    +-- UnicodeError  # 发生与Unicode相关的编码或解码错误

      |         +-- UnicodeDecodeError  # Unicode解码错误

      |         +-- UnicodeEncodeError  # Unicode编码错误

      |         +-- UnicodeTranslateError  # Unicode转码错误

      +-- Warning  # 警告的基类

           +-- DeprecationWarning  # 有关已弃用功能的警告的基类

           +-- PendingDeprecationWarning  # 有关不推荐使用功能的警告的基类

           +-- RuntimeWarning  # 有关可疑的运行时行为的警告的基类

           +-- SyntaxWarning  # 关于可疑语法警告的基类

           +-- UserWarning  # 用户代码生成警告的基类

           +-- FutureWarning  # 有关已弃用功能的警告的基类

           +-- ImportWarning  # 关于模块导入时可能出错的警告的基类

           +-- UnicodeWarning  # 与Unicode相关的警告的基类

           +-- BytesWarning  # 与bytes和bytearray相关的警告的基类

           +-- ResourceWarning  # 与资源使用相关的警告的基类。被默认警告过滤器忽略。

3 异常捕获与处理

  当发生异常时,我们就需要对异常进行捕获,然后进行相应的处理。使用Python异常处理机制时,把可能发生错误的语句放在try模块里,用except来处理异常,每一个try,都必须至少对应一个except。Python异常处理机制常用的几种异常捕获和处理结构如下:

  第一种:try - except

try:

    <语句>

except:

    <异常处理>

  这种结构使用简单,但可能会引发一些设计问题:尽管使用方便,但可能捕获与程序无关、意料之外的系统异常,而且可能意外拦截其他处理器的异常。例如,在Python中,即表示系统离开调用(sys.exit())也会出发异常,然而这种异常我们通常不需要捕获。所以,这种结构尽量少用。

import time

import sys

try:

    while True:

        a = int(input('请输入一个数字:'))

        if a==0:

            sys.exit()

        else:

            print('您输入的数字是:{}'.format(a))

        time.sleep(1)

except:

    print('发生异常了……')

  当输入数字0时,输出如下:

  请输入一个数字:0

  发生异常了……

  事实上,系统知识正常退出,并不算异常,但是只使用except,Python会将系统离开调用当做异常来捕获。

  (2)try-except<异常名>

try:

    <语句>

 except <异常名> [as e]:

    <异常处理>

  except中,as e是可选的,意思是将捕获的异常类实例化对象赋值给e(当然也可以用其他变量名),在except下面的代码块中,我们将可以通过这个e访问异常实例化对象中的方法和数据。另外,except子句的个数理论上是不限的,不过不能将父类置于子类前面。在上文中提到,Exception类是所有Python异常类的父类,所以except Exception将可以捕获任何异常,换句话说,它是万能异常处理句式。

try:

    a = int(input('请输入一个数字:'))

except ValueError as e:

    print(e)

  当输入一个非数字类字符时,输出如下:

  请输入a的值:j

  invalid literal for int() with base 10: 'j'

  如果输入b的值为0,输出如下:

  请输入a的值:1

  请输入b的值:0

  division by zero

  (3)try-except (<异常类1>, <异常类2>, ...)

try:

    <语句>

except (<异常类1>, <异常类2>, ...):

    <异常处理>
try:

    a = int(input('请输入a的值:'))

    b = int(input('请输入b的值:'))

    c = a/b

except (ValueError , ZeroDivisionError) as e:

    print(e)

  当输入一个非数字类字符时,输出如下:

  请输入a的值:j

  invalid literal for int() with base 10: 'j'

  如果输入b的值为0,输出如下:

  请输入a的值:1

  请输入b的值:0

  division by zero

  (4)try-except-else

try:

    <语句>

except <异常名>:

    <异常处理>

else:

    <语句>  # try语句中没有异常则执行此段代码

  如果说except是在try中代码抛出异常时执行,那么else语句下面的代码将在try顺利执行(没有抛出任何异常)的情况下才会执行。

try:

    a = int(input('请输入a的值:'))

    b = int(input('请输入b的值:'))

    c = a/b

except (ValueError , ZeroDivisionError) as e:

    print(e)

else:

    print('a/b的结果为:{}'.format(c))

  当输入a和b的值都为数字时,才会执行else部分代码,输出结果如下:

  请输入a的值:4

  请输入b的值:2

  a/b的结果为:2.0

  (5)try-except-finally

try:

    <语句>

except <异常类>:

    <异常处理>

finally:

    <语句>  # 不管try中代码是否抛出异常,都会执行此段代码

  finally中的代码无论try中代码是否抛出异常都会执行。

try:

    a = int(input('请输入a的值:'))

    b = int(input('请输入b的值:'))

    c = a/b

except (ValueError , ZeroDivisionError) as e:

    print(e)

else:

    print('a/b的结果为:{}'.format(c))

finally:

    print('无论你输入什么值,finally都会执行……')

4 主动抛出异常(raise)

  有时候,异常可以作为代码运行的标志,通过主动触发异常可以改变代码的运行路线,从而提高代码健壮性。主动触发异常需使用raise关键字,其语法结构如下:

  raise [Exception [, args [, traceback]]]
def fun(x , y):

    try:

        print('fun()方法开始执行……')

        if isinstance(x,int) and isinstance(y,int):

            return x+y

        else:

            raise TypeError('类型错误')

    except Exception as e:

        print(e)

    finally:

        print('fun()方法执行结束……')

fun(2 , '')

  输出结果:

  fun()方法开始执行……

  类型错误

  fun()方法执行结束……

5 断言(assert)

  assert语句根据后面的表达式的真假来控制程序流。 asset语法结构如下:

assert expression,'information'

若为expression结果为True,则往下执行。若为False,则中断程序并调用默认的异常处理器抛出AssertionError异常,同时输出指定的提示信息。

def fun(x):
print('fun()方法开始执行……')
assert x<0 , '抛出异常,x小于0'
print('fun()方法执行结束……')
try:
fun(2)
except Exception as e:
print(e)

  输出结果:

  fun()方法开始执行……
  抛出异常,x小于0

  可以发现,打印输出第一行语句之后,由于断言失败,抛出异常,程序直接退出。

6 with/as上下文管理器

  with/as语句通常是作为try/finally语句的替代方案,不过with/as更加优雅。在有一些任务中,可能事先需要设置,然后不管在任务过程中是否顺利(有无异常抛出),最后后做清理工作。对于这种场景, with/as语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读写数据,但不管读写数据是否有异常发生,最后都要关闭文件句柄。

  with/as语句的基本格式如下:

with expression [as variable] :

    with-block

  在这里的expression会返回一个对象,as子句是可选的,当存在as子句时,expression返回的对象会赋值给variable。

  使用with/as语句将一段字符串写入文件:

with open('data.txt' , 'w') as myfile:

    myfile.write('')

         不适用with/as语句,如果要实现同样的效果,只能这么写:

try:

    myfile = open('data.txt' , 'w')

    myfile.write('')

except Exception as e:

    print(e)

finally:

    myfile.close()

7 自定义异常类

如果Python提供的内置异常内不满足使用要求,那么,可以自定义一个异常类。自定义异常类必须继承Exception类,并且在使用时,必须通过raise关键字自动触发。

class MyError(Exception):

    def __init__(self, info):

        self.info = info

    def __str__(self):

        return '{}:{}'.format(self.__class__ .__name__, self.info)

try:

    raise MyError('自定义的异常……')

except MyError as e :

print(e)

  输出结果:

  MyError:自定义的异常……

8 总结

  本文是对Python异常处理机制的总结,较为全面的介绍了Python异常处理的常用内置类,即几种异常捕获/处理句式结构,主动触发异常,断言,with上下文管理协议,自定义异常类等内容。

Python异常处理回顾与总结的更多相关文章

  1. python异常处理(基础)

    之前在学习python的时候有整理过python异常处理的文章,不够简单也不够完整,所以决定再整理一篇,算做补充. http://www.cnblogs.com/fnng/archive/2013/0 ...

  2. Python异常处理 分类: python Raspberry Pi 服务器搭建 2015-04-01 13:22 172人阅读 评论(0) 收藏

    一个程序要保持稳定运行必须要有异常处理,本文将简单介绍Python中的try-except..异常处理语句的使用. 该种异常处理语法的规则是: 执行try下的语句,如果引发异常,则执行过程会跳到第一个 ...

  3. Python 异常处理--raise函数用法

    raise语句手工引发一个异常: "raise" [expression ["," expression ["," expression]] ...

  4. [Python学习笔记][第八章Python异常处理结构与程序调试]

    1/30 第八章Python异常处理结构与程序调试 异常处理 try-except结构 try: try块 except Exception: except块 try-except-else结构 tr ...

  5. python异常处理try,except,else,finally,raise

    先看下else的使用: try: ... exception: ... else: ... 只有在try中没有发生任何异常,所有代码完全成功的情况下才会转入else 再看下finally: final ...

  6. Python 异常处理

    Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误.你可以使用该功能来调试python程序. 异常处理: 本站Python教程会具体介绍. 断言 ...

  7. python异常处理的哲学

    所谓异常指的是程序的执行出现了非预期行为,就好比现实中的做一件事过程中总会出现一些意外的事.异常的处理是跨越编程语言的,和具体的编程细节相比,程序执行异常的处理更像是哲学.限于认知能力和经验所限,不可 ...

  8. Python异常处理总结

    一.何谓异常处理 在我们调试程序时,经常不可避免地出现意料之外的情况,导致程序不得不停止运行,然后提示大堆提示信息,大多是这种情况都是由异常引起的.异常的出现一方面是因为写代码时粗心导致的语法错误,这 ...

  9. python异常处理与断言以及日志模块

    python异常处理与断言 目录: 1.异常处理 2.断言(assert) 3.日志模块(logging) 4.修改之前的车票信息查询,把日志模块.异常处理加进去 1.异常处理 代码如下: 语法: t ...

随机推荐

  1. 函数和常用模块【day06】:shutil模块(四)

    本节内容 简书 模块详解 压缩解压 一.简述 我们在日常处理文件时,经常用到os模块,但是有的时候你会发现,像拷贝.删除.打包.压缩等文件操作,在os模块中没有对应的函数去操作,下面我们就来讲讲高级的 ...

  2. SQL记录-PLSQL-DBMS输出

    PL/SQL DBMS输出   DBMS_OUTPUT是一个内置的软件包,能够显示输出显示调试信息,并从PL/ SQL块,子程序,包和触发器发送消息.我们已经使用这个包在我们所有的教程中. 让我们来看 ...

  3. 「MYSQL」MYSQL中的int(11)到底代表什么意思?

    一.前言 在工作中经常要与mysql打交道,但是对mysql的各个字段类型一直都是一知半解,因此写本文总结记录一番. 二.简介 对于int类型的一些基础知识其实上图已经说的很明白了,在这里想讨论下常用 ...

  4. Codeforces Round #477 (rated, Div. 2, based on VK Cup 2018 Round 3) E 贪心

    http://codeforces.com/contest/967/problem/E 题目大意: 给你一个数组a,a的长度为n 定义:b(i) = a(1)^a(2)^......^a(i), 问, ...

  5. LaTeX符号和图片

    \documentclass{article} \usepackage{ctex} %中文处理 \begin{document} \section{空白符号} Are you wiser than o ...

  6. Docker 入门 第二部分: 容器

    目录 Docker 入门 第二部分: 容器 先决条件 介绍 你的新开发环境 使用 Dockerfile 定义一个容器 Dockerfile 应用本身 requirements.txt app.py 构 ...

  7. Python super() 函数

    super() 函数是用于调用父类(超类)的一个方法. super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果重定义某个方法,该方法会覆盖父类的同名方法,但有时 ...

  8. 第10月第6天 lua 闭包

    1. static int mytest(lua_State *L) { //获取上值 )); printf("%d\n", upv); upv += ; lua_pushinte ...

  9. python垃圾回收三之标记清除

    #第一组循环引用# a = [1,2] b = [3,4] a.append(b) b.append(a) del a ## #第二组循环引用# c = [4,5] d = [5,6] c.appen ...

  10. phantomjs 长图截屏

    var page = require('webpage').create(); var url = 'http://cardloan9.hateblo.jp/'; page.settings = { ...