python异常处理

异常

在程序 运行 时,如果发生 错误 ,会阻止程序正常运行,就是 异常。

错误和异常的区别

错误

下面这两种错误,是人为造成的,那么就是错误

  1. 语法错误
  2. 逻辑错误

异常

异常也是错误,但与上述的错误不同。程序编写正确,是用户没正确操作导致的错误,即:在 运行 时发生 错误,像下面这些错误就是 异常

  1. 用户输入不合法的数据,如:执行 1/0
  2. 网络连接中断
  3. 打开不存在的文件
  4. 将文件保存到不存在的盘符
  5. 内存空间不够

异常的产生

像下面这种情况,执行报错,会抛出ZeroDivisionError异常,并且 后面的代码不会运行:

print("----欢迎使用除法计算器-----")
a = input("请输入被除数:")
b = input("请输入除数:")

a = float(a)
b = float(b)

res = a/b
print("除法结果:",res)

执行 8/4 可以正常运行

执行 9/0 报错如下:

ZeroDivisionError: division by zero

总结

不同的语言对错误处理并不一样,C语言中,用 函数返回值 表示 正确 或者 错误 ,处理起来不方便

高级语言都有异常处理机制,当出现错误时会 抛出异常

python也是如此。在python中, 异常也是类 , 都继承BaseException,当出现错误时会抛出 异常类对象,错误信息保存在异常类对象中

处理一个异常

语法

如果认为某些代码可能会出错时,就可以用try...except...来处理

语法格式如下:

try:
    可能抛异常的代码
except 异常类 [as 异常对象]:
    处理异常。如:打印错误信息

后续代码

as 异常对象可以省略

执行说明:

  1. 可能抛异常的代码不报错,except代码块忽略掉,直接执行后续代码
  2. 可能抛异常的代码报错,就中止运行并抛出异常,根据抛出 异常 的 类型 ,找到与之相匹配的except 异常类,然后执行处理异常。
    如果没有找到与之相匹配的except,就由python解释器处理,即:中止运行

例子1

print("----欢迎使用除法计算器-----")
a = input("请输入被除数:")
b = input("请输入除数:")

a = float(a)
b = float(b)

try:
    print("1.进入 try 代码块")
    res = a/b
    print("除法结果:",res)
    print("2.try代码块执行结束")
except ZeroDivisionError as e: # e是异常对象,封装异常的信息
    print("3.进入 except 代码块")
    print(e)
    print("4.except代码块执行结束")

print("程序执行结束")

正常运行执行过程

输入 8、2,正常执行时,except 代码块不会执行,过程如下:

抛出异常执行过程

输入 8、0,抛出异常,异常类型与 except ZeroDivisionError 匹配,那么执行 except 代码块,然后继续运行后面的代码

处理异常

异常信息是英文提示,如下:

改为中文提示,修改 except 代码块,如下:

# print(e)
print("除数不能是0!")

省略 as e

如果不需要打印异常信息,可以省略as e,如下:

try:
    i=1/0 #会抛异常
    j=10 #抛异常后,不会运行此行代码
except ZeroDivisionError:
    print('0不能是被除数')

s='hello world'

例子2

try:
    i=1/0 #会抛异常
    j=10 #抛异常后,不会运行此行代码
except TypeError as e:
    print('except:',e)#抛异常后会执行此行代码
s='hello world'

抛出异常,异常类型与except TypeError 不匹配,就由python解释器处理,即中止运行

例子3

将 例子1 改造成函数

def test(i,j):
    try:
        r=i/j
        return r
    except ZeroDivisionError as e:
        print('except:',e)#抛异常后会执行此行代码

    print('捕捉ZeroDivisionError异常时,本行文字才会打印')

调用执行:

#正常运行
a=test(1,1)
print(a+5)

#当传入0时,抛ZeroDivisionError异常,并会处理异常
a=test(1,0)
print(a+5)

'''
当传入字符串时,报TypeError错误,except代码块中没有捕捉这个异常,所以不会处理,而是直接抛出
'''
a=test(1,'0')
print(a+5)

缺点

无法处理多个错误

处理多个异常

为了解决上面例子的问题,需要用多个 except 代码块处理不同的异常

语法

try:
    可能抛异常的代码
except 异常类1 [as 异常对象1]:
    处理异常1。如:打印错误信息
except 异常类2 [as 异常对象2]:
    处理异常2。如:打印错误信息
......

后续代码

例子4

完善例子3
将 例子1 改造成函数

def test(i,j):
    try:
        r=i/j
        return r
    except ZeroDivisionError as e:
        print('except:',e)
    except TypeError as e:
        print('except:',e)

    print('捕捉ZeroDivisionError异常时,本行文字才会打印')

调用执行:

#正常运行
a=test(1,1)
print(a+5)

#当传入0时,抛ZeroDivisionError异常,并会处理异常
a=test(1,0)
print(a+5)


#当传入字符串时,抛TypeError异常,并会处理异常

a=test(1,'0')
print(a+5)

缺点
这种处理错误的方法,会出现bug:报错后,只是打印错误信息,导致上层程序不知道运行是否正确,特别是返回值为None,无法继续运算。

注意:
很多时候,不要只是 打印异常信息,如果不知道怎么处理错误,就 抛出异常

处理异常的顺序

在python中,异常也是类,都继承BaseException,在使用except时要注意,不但捕获该类型的错误,也会 处理其子类类型的异常

内置异常类说明:
http://www.malaoshi.top/show_1EF2I6EXS38I.html

将上面的代码改造

def test(i,j):
    try:
        r=i/j
        return r
    except BaseException as e:
        print('都被父类异常捕捉,except:',e)
    except ZeroDivisionError as e2:
        print('被除数不能是0')
    except TypeError as e3:
        print('只能传入int和float')

    print('报错时才会打印本行文字')

调用执行

a=test(1,1)
print(a)
print(a+5)
a=test(1,0)
print(a)
print(a+5)
a=test(1,'1')
print(a)
print(a+5)

注意:
第一个except BaseException as e:代码块的异常类是BaseException,会捕获到所有异常错误,导致后面的except代码块都失效了

所以要将 子类异常写在上面 ,父类异常写在下面

finally关键字

有两种写法,一种是try...except...finally...,一种是try...finally...

语法1

try:
    可能抛异常的代码
except 异常类 as 异常对象:
    处理异常,如:打印错误信息
finally:
    一定会执行的代码

执行顺序:

  1. try代码块中不抛异常,正常执行try代码块,然后执行finally代码块
  2. try代码块抛异常,中止运行try代码块,如果异常类型与except 异常类相匹配,就执行except代码块,然后执行finally代码块
  3. 如果异常类型与except 异常类都不匹配,就执行finally代码块,最后由python解释器处理异常

注意:
不论是否抛异常,不论except代码块是否执行,一定执行 finally代码块

应用场景

一般用于清理、回收等操作。

在读写文件时,读写文件不论是否抛出异常,读写后都应该 释放 文件对象,那么就将 释放文件对象 的操作放入 finally 代码块中。

操作数据库也是如此。

语法2

except可以省略

try:
    可能抛异常的代码
finally:
    一定会执行的代码

执行顺序:

  1. try代码块中不抛异常,正常执行try代码块,然后执行finally代码块
  2. try代码块抛异常,中止运行try代码块,然后执行finally代码块,最后由python解释器处理异常

例子5-语法1

path = input("请输入要读取的文件路径:")

try:
    f = open(path,'r',encoding='utf-8')
    print(f.read())
    f.close()
except FileNotFoundError as e:
    # print(e)
    print("读取失败,文件不存在:",path)

print("程序执行结束")
打开存在文件时

输入存在文件时,能够正常运行

打开不存在文件时

输入不存在文件路径时,会报错,如下:

改进1

加上 finally 代码块,将 关闭文件代码 写在该代码块中

path = input("请输入要读取的文件路径:")

try:
    f = open(path,'r',encoding='utf-8')
    print(f.read())
except FileNotFoundError as e:
    # print(e)
    print("读取失败,文件不存在:",path)
finally: # 永远都会执行
    print("1.进入finally代码块")
    f.close()
    print("2.finally代码块执行结束")

print("程序执行结束")
打开存在文件时

正常运行时,会执行 finally 代码块

打开不存在文件时

打开不存在文件时,先执行 except 代码块,然后执行 finally 代码块,但会报错,如下图:

改进2

path = input("请输入要读取的文件路径:")

f = None
try:
    f = open(path,'r',encoding='utf-8')
    print(f.read())
except FileNotFoundError as e:
    # print(e)
    print("读取失败,文件不存在:",path)
finally:  # 永远都会执行
    print("1.进入finally代码块")
    if f:
        f.close()
    print("2.finally代码块执行结束")

print("程序执行结束")

总结

如果有 finally,那么一定会执行 finally 代码块,即使在 try 中 return 结果,也会执行finally 代码块

例子6-语法2

def test(i,j):
    try:
        r=i/j
        return r
    finally:
        print('finally代码块')

    print('捕捉ZeroDivisionError异常时,本行文字才会打印')

test(1,'2')

else关键字

语法

try:
    可能抛异常的代码
except 异常类 as 异常对象:
    处理异常,如:打印错误信息
else:
    没有异常时执行
finally:
    一定会执行的代码

执行顺序:
当try代码块没有抛异常时,就会执行else代码块

注意:return语句不要写在try代码块中,否则不会执行eles代码块

例子7

def test2(i,j):
    try:
        r=i/j
    except ZeroDivisionError as e:
        print('except:',e)#抛异常后会执行此行代码
    else:
        print('没有异常')
    finally:
        print('finally代码块')

    print('捕捉ZeroDivisionError异常时,本行文字才会打印')

    return r
print(test2(1,2))

注意:

return 语句不要写在 try 代码块中,否则不会执行 eles 代码块

raise抛出异常

一般用在函数中,比如登录,当登录失败时,就抛出异常,由外部程序处理异常

def login(username,password):

    if username == 'lilei' and password == '123456':
        return True
    else:
        raise Exception('用户名或密码错误!')



username = input("请输入用户名:")
password = input("请输入密码:")

try:
    res = login(username,password)
    if(res):
        print("登录成功!")
except Exception as e:
    print(e)

感谢链接:
http://www.runoob.com/python/python-exceptions.html


原文出处:/show_1EF2HrDzoltS.html