Python3.5从0开始学读书笔记——第九章 异常

版权声明:版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_26489189/article/details/82753397

什么是异常

一般情况下,在Python无法正常处理程序时就会发生异常。异常是Python的对象,表示一个错误。当Python脚本发生异常时,我们需要捕获并处理异常,否则程序会终止执行。如:

print(a)

输出:

Traceback (most recent call last):
  File "D:/pyspace/hellopython/Chapter9.py", line 1, in <module>
    print(a)
NameError: name 'a' is not defined

异常处理

处理异常,最简单的是使用try语句处理。try语句的基本格式为:try/except。try/except语句用来检测try语句块中的错误,从而让except语句捕获异常信息并处理。如果你不想在发生异常时结束程序,只需要在try语句块中捕获异常即可。语法格式如下:

try:
    <语句> #运行别的代码
except<异常的名字>:
    <语句> #如果在try部分发生了异常
    

示例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def test_exception(x,y):
    try:
        a = x/y
        print('a=',a)
        return a
    except Exception:
        print('程序发生异常,被除数为0')

test_exception(10,0)

输出:

程序发生异常,被除数为0

抛出异常

Python使用raise语句抛出一个指定的异常。使用类时程序会自动创建实例。

#raise Exception

#raise NameError('this is nameerror')

def test_exception2():
    try:
        raise NameError('This is a NameError')
    except NameError:
        print('发生异常!')
        #raise 如果只想知道是否抛出了异常,不想处理。加上raise语句把异常再次抛出

test_exception2()

输出(捕获异常后不添加raise):

发生异常!

输出(捕获异常后添加raise):

Traceback (most recent call last):
发生异常!
  File "D:/pyspace/hellopython/Chapter9.py", line 26, in <module>
    test_exception2()
  File "D:/pyspace/hellopython/Chapter9.py", line 21, in test_exception2
    raise NameError('This is a NameError')
NameError: This is a NameError

在Python中,内建的异常类很多,比如:NameError、SyntaxError、TypeError、ValueError等,可以使用dir函数列出异常类的内容,并用在raise语句中。内建的异常类如表格:

异常名称 描述
Exception 常规错误的基类
AttributeError 对象没有这个属性
IOError 输入/输出操作失败
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
NameError 未声明/初始化对象
SyntaxError 语法错误
SystemError 一般解释器系统错误
ValueError 传入无效的参数

捕获多个异常

Python支持在一个try/excpet语句中处理多个异常,语法如下:

try:
    <语句>
except <异常名1>:
    <语句>
except <异常名2>:
    <语句>

示例如下:

def test_expcetion3(a,b):
    try:
        c = a / b
        #c = name
        return c
    except ZeroDivisionError:
        print('除数不能为0')
    except NameError:
        print('对象未声明')

test_exception(10,0)

输出:

程序发生异常,被除数为0

使用一个块捕捉多个异常

如果需要使用一个块捕捉多个类型异常,可以将它们作为元组列出。使用该方式时,遇到的异常类型是元组中的任意一个,都会走异常流程。实例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
def test_expceiton4(a,b):
    try:
        c = a/b
        return c
    except (ZeroDivisionError,NameError,TypeError):
        print('发生了异常!')

test_expceiton4(10,0)

输出:

发生了异常!

如果我们希望多个except字句输出同样的信息,就没必要在几个except字句中重复输入字句,放到一个异常块中即可。

捕捉对象

如果需要输出错误时的栈堆信息,可以使用as e的形式,我们称之为捕捉对象。实例如下:

def test_expceiton5(a,b):
    try:
        c = a/b
        return c
    except (ZeroDivisionError,NameError,TypeError) as e:
        print(e)

test_expceiton5(10,0)

输出:

division by zero

全捕捉

对于逃过了捕获指定异常的情况,我们根本无法预测会发生什么,也无法提前做任何准备。此时,与其使用不是捕获异常try/catch语句隐藏异常,不如让程序立刻崩溃。实例如下:

def test_expceiton5(a,b):
    try:
        c = a/b
        return c
    except:
        print('全捕获异常')

test_expceiton5(10,'')

输出:

全捕获异常

异常中的else

try…except…else…语句,如果在try语句执行时没有发生异常,就会执行else语句后的语句(如果有else)。使用else语句,比把所有语句都放在try字句里更好,这样可以避免一些意想不到而except有没捕获的异常。格式如下:

try<语句>
except<异常名1>:
    <语句>
except<异常名n>:
    <语句>
else:
    <语句> #如果没有发生异常

示例如下:

def test_expceiton6(a,b):
    try:
        c = a/b
    except:
        print('全捕获异常')
    else:
        print('没有发生异常')

test_expceiton6(10,5)

输出:

没有发生异常

自定义异常

尽管内建异常包含了大部分异常,可以满足很多要求,但有时还是要创建自己的异常类。可以通过创建一个新的exception类拥有自己的异常,异常应该继承自Exception类,可以直接继承,也可以间接继承。

因为错误就是类,因此捕获异常就是捕获该类的一个实例,我们自己编写的函数也可以抛出错误。如果要抛出错误,那么可以定义一个错误类,根据需要选择好继承关系,然后用raise语句抛出一个错误的实例。示例如下:

#! /usr/bin/python3
# -*- coding:UTF-8 -*-
# 自定义异常类最好以Error结尾,方便识别
class MyError(Exception):
    def __init__(self):
        pass

    def __str__(self):
        return 'this is my error'

def my_error_test():
    try:
        raise MyError()
    except MyError as e:
        print('exception e is:',e)

my_error_test()

输出:

exception e is: this is my error

finally子句

Python中finally子句需要和try语句一起使用,组成try/finally的语句形式,try/finally语句无论是否发生异常与否都将执行最后的代码。try、except、else、finally语句可以组合使用,执行顺序为:else在except之后,finally在except和else之后。示例如下:

def use_finally(a,b):
    try:
        c = a/b
        print('c=',c)
    except Exception:
        print('发生异常')
    else:
        print('顺利上岸,没有发生异常')
    finally:
        print('不管是否发生异常,我都会出现!')

use_finally(10,0)#测试发生异常
#use_finally(10,5)#测试不发生异常

发生异常时,输出:

发生异常
不管是否发生异常,我都会出现!

不发生异常时,输出:

c= 2.0
顺利上岸,没有发生异常
不管是否发生异常,我都会出现!

异常和函数

如果异常在函数内引发而不被处理,就会传播至函数调用的地方。如果异常在函数调用的地方也没有被处理,就会继续传播,一直到达主程序。如果在主程序也没有被处理,异常就会被Python解释器捕获,输出一个错误信息,然后退出主程序。示例如下:

def divide_func(a,b):
    return a/b

def exec_divide_func(a,b):
    return divide_func(a,b)*10

def main(a,b):
    return exec_divide_func(a,b)

main(10,0)

输出:

Traceback (most recent call last):
  File "D:/pyspace/hellopython/Chapter9.py", line 131, in <module>
    main(10,0)
  File "D:/pyspace/hellopython/Chapter9.py", line 129, in main
    return exec_divide_func(a,b)
  File "D:/pyspace/hellopython/Chapter9.py", line 126, in exec_divide_func
    return divide_func(a,b)*10
  File "D:/pyspace/hellopython/Chapter9.py", line 123, in divide_func
    return a/b
ZeroDivisionError: division by zero

由执行结果来看,divide_func函数中产生的异常通过divide_func和exec_divide_func函数传播,exec_divide_func函数中的异常,通过exec_divide_func和main函数传播,传播到函数调用处后由Python解释器处理,最终抛出栈堆异常。

猜你喜欢

转载自blog.csdn.net/qq_26489189/article/details/82753397