了解python之异常处理

目录

概念

  • try工作原理
  • 捕获异常的语法

抛出异常

python捕获多个异常

捕捉对象

异常中的else

自定义异常

try中的finally子句

 


 

 

概念:

程序运行过程中出现的报错,我们称之为错误,也可以称为异常,或者说程序没有按照预期运行。错误都是异常,但异常并不一定都是错误

python运行的程序报错,常见有NameError、SyntaxError、TypeError、ValueError等,这些都称为异常。异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行

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

 

例1:

print(a)

##输出结果:
NameError: name 'a' is not defined

 

try的工作原理:
开始一个try语句后,python就在当前的程序上下文中做标记,当出现异常时,就可以回到做标记的地方,首先需要执行try子句,接下来发生什么依赖于执行时是否出现异常。如果try后的语句执行时发生异常,程序就跳回try并执行except子句。异常处理完毕,控制流就可以通过整个try语句了(除了在处理异常时又引发了新的异常)

 

捕获异常的语法:

try:
  <语句>
except<名字>:
   语句    #如果try部分引发了异常,执行这个语句

 

例2:

def exp_exception(x,y):
    try:
        a=x/y
        print('a=',a)
        return a
    except Exception:
        print('程序出现异常,异常信息是:被除数是0')

exp_exception(2,0)

##输出结果
程序出现异常,异常信息是:被除数是0

 

抛出异常

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

例3:

raise Exception

##输出结果:
    raise Exception
Exception


//


raise NameError('this is NameError')
##输出结果:
    raise NameError('this is NameError')
NameError: this is NameError

例4:

try:
    raise NameError('This is NameError')
except NameError:
    print('An exception happened..')  
    #不带raise语句

##输出结果:
An exception happened..


///

try:
    raise NameError('This is NameError')
except NameError:
    print('An exception happened..')
    raise

##输出结果:
    raise NameError('This is NameError')
NameError: This is NameError
An exception happened..

 

使用raise可以输出更深层次的异常,在使用过程中,可以借助这个方法得到更详细的信息。

 

我们之前说的异常:NameError、SyntaxError、TypeError、ValueError等异常类称为内建异常类。在python中,内建的异常类有很多,可以使用dir函数罗列出异常类的内容,并用在raise语句中,如raise NameError这种,下面列举出一些常见的异常类:

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

 

python捕获多个异常

python怎么捕获多个异常,python支持在一个try ... except语句处理多个异常,语法如下:

try:
  <语句>   #运行的代码
except<name1>:
  <语句>  #如果在try部分触发了name1异常,就会执行这个语句
except<name2>:
   <语句>  #如果在try部分引发了name2异常,执行这个语句

 

一个try可以包含多个except子句,但子句中只有一个分支会被处理,而且是按照顺序处理的。

例5:

def mult_exception(x,y):
    try:
        a=x/y
        b=name
    except ZeroDivisionError:
        print('This is ZeroDivisionError')
    except NameError:
        print('This is NameError')

mult_exception(2,0)

##输出结果:
This is ZeroDivisionErro


///

def mult_exception(x,y):
    try:
        b=name
        a=x/y
    except ZeroDivisionError:
        print('This is ZeroDivisionError')
    except NameError:
        print('This is NameError')

mult_exception(2,0)

##输出结果:
This is NameError

/

def mult_exception(x,y):
    try:
        a=x/y
        b=name
    except (ZeroDivisionError,NameError,TypeError):
        print('This is ZeroDivisionError or NameErr or TypeError ')

mult_exception(2,0)

##输出结果:
This is ZeroDivisionError or NameErr or TypeError

 

捕捉对象:

如果希望在except子句中访问异常对象的本身,也就是看到一个异常对象真正的异常信息,而不是输出自己定义的异常信息,可以使用as e的形式,我们称之为捕捉对象,如:

例6:

def model_exception(x,y):
    try:
        b=name
        a=x/y
    except (ZeroDivisionError,NameError,TypeError) as e:
        print(e)

model_exception(2,0)

##输出结果:
name 'name' is not defined

//

def model_exception(x,y):
    try:
        a=x/y
        b=name
    except (ZeroDivisionError,NameError,TypeError) as e:
        print(e)

model_exception(2,0)

##输出结果:
division by zero

可以看到:执行的过程中抛出异常被截获并正常输出了相关的异常信息,并且使用这个方式可以捕捉多个异常。

 

全捕捉:可以捕捉到所有异常

例7:

def model_exception(x,y):
    try:
        a=x/y
        b=name
    except (ZeroDivisionError,NameError,TypeError) as e:
        print(e)

model_exception(2,'')

##输出结果:
unsupported operand type(s) for /: 'int' and 'str'

可以看到try/except这块的异常被隐藏了,并没有被捕捉到,如果想要处理这种异常,怎么办?

def model_exception(x,y):
    try:
        a=x/y
        b=name
    except:
        print('Error happened')

model_exception(2,'')

##输出结果:
Error happened

 

异常中的else

如果程序执行完异常还需要做其他事情,怎么办?可以使用try ...except...else语句实现这个功能,语法:

try:
  <语句>  #运行的代码
except<名字>:
  <语句>   #在try部分如果引发了异常,执行这个位置的语句
except<名字2>,<数据>:
  <语句>   #如果在try部分引发了第二个异常,则获得附加数据
else:
  <语句>    #如果没有发生异常执行这个语句

例8:

def model_exception(x,y):
    try:
        a=x/y
    except:
        print('Error happened')
    else:
        print('It went as excepted')

model_exception(2,1)

##输出结果:
It went as excepted

 

自定义异常:异常类继承来自Exception类,可以直接继承,也可以间接继承。

例9:

class MyError(Exception):
    def __init__(self):
        pass
    def __str__(self):
        return 'This is self define error'

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

my_error_test()

##输出结果:
exception info: This is self define error

可以看到,程序正确的执行了自定义的异常,并且需要继承Exception类。上面只是一个简单的例子,还有很多细节需要去研究。

 

try中的finally子句

python中的finally子句需要和try子句一起使用,组成try/finally语句形式,try/finally语句无论发生异常与否,都会执行最后finally的代码。

例10:

def use_finally(x,y):
    try:
        a=x/y
    finally:
        print('No matter what happened,I will show in front of you')

use_finally(2,0)

##输出结果:
No matter what happened,I will show in front of you
ZeroDivisionError: division by zero

try..except..else..finally组合使用,else必须在except之后,finally在except和else之后。上面的例子可以改成如下:

def use_finally(x,y):
    try:
        a=x/y
    except ZeroDivisionError:
        print('division is zero')
    finally:
        print('No matter what happened,I will show in front of you')

use_finally(2,0)

##输出结果:
division is zero
No matter what happened,I will show in front of you

 

深入拓展学习:

Python异常处理详解

Python with/as和contextlib上下文管理使用说明