Python学习|Python学习-错误和异常的处理

Python 有两种错误很容易辨认:语法错误和异常。
Python assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常。
关键字:1、assert raise ; 2、try except else finally
1 语法错误(也称解析错误) 【Python学习|Python学习-错误和异常的处理】例子:

while True print('hello world')

执行结果:
File "D:/错误和异常.py", line 11 while True print('hello world') ^ SyntaxError: invalid syntax

在上面的语句中,函数print()被检查到有语法错误,原因是它print()前面缺了一个冒号:,同时语法分析器指出了出错的地方的行数,并且在最先找到的错误的位置标记了一个小小的箭头。
2 异常 有时候Python程序的语法是正确的,在运行的时候也有可能发生错误,这种错误被称为异常。
大多数的异常都不会被程序处理,都以错误信息的形式展现出来。
a = 10 / 0# 0 不能作为除数,触发异常: ZeroDivisionError: division by zero b =1 + x * 2# x 未定义,触发异常:NameError: name 'x' is not defined c= '1' + 1# 整型int和字符串str 不能相加,触发异常: TypeError: must be str, not int

异常以不同的类型出现,这些类型都作为信息的一部分打印出来,上面中的异常类型有: ZeroDivisionError、NameError 和 TypeError。错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体信息。
2.1 异常的传播
  • 当在函数中出现异常时,如果没有对异常进行了处理,则异常不再继续传播;如果没处理,则异常会继续向函数调用处传播,直至传递到全局作用域;如果依然没处理,则程序终止,并返回异常信息。
  • 当程序在运行的过程中出现异常,所有异常信息会保存到一个专门的异常对象(驼峰命名法的一个类)中,而异常传播是,实际就是异常对象抛给了调用处。
  • 所有内置的、非系统退出的、用户定义的异常都派生于Exception(父类)
2.2 异常处理
  • try语句:
try: 代码块(可能出现错误的语句) except 异常类型 as 异常名: 代码块(出现错误以后的处理方式) except 异常类型 as 异常名: 代码块(出现错误以后的处理方式) except 异常类型 as 异常名: 代码块(出现错误以后的处理方式) ... else: 代码块(没出错时要执行的语句) finally: 代码块(是否出错该代码块都会执行)

  • try语句的工作方式:
    (1)首先,执行 try 子句(在关键字 try 和关键字 except 之间的语句)。
    (2)如果没有异常发生,忽略 except 子句,try 子句执行后结束。
    (3)如果在执行 try 子句的过程中发生了异常,那么 try 子句余下的部分将被忽略。
    如果异常的类型和 except 之后的名称相符,那么对应的 except 子句将被执行。
    (4)如果一个异常没有与任何的 except 匹配,那么这个异常将会传递给上层的 try 中。
  • 注意:
    (1)try是必须的,else有没有都可以,except和finally至少有一个。
    (2)一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常, 但最多只有一个分支会被执行。
    (3)处理程序将只针对对应的 try 子句中的异常进行处理,而不是其他的 try 的处理程序中的异常。
    (4)一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:
    except (ZeroDivisionError,NameError,TypeError):
    pass
    (5)最后一个except子句可以忽略异常的名称,它将被当作通配符使用。
  • try/except语句:捕获异常
while True: try: x = int(input("请输入一个数字: ")) break except ValueError: print("您输入的不是数字,请再次尝试输入!")

使用快捷键Ctrl+c或者操作系统提供的方法可以中断该程序,并引发一个KeyboardInterrupt异常,执行结果:
请输入一个数字: ds 您输入的不是数字,请再次尝试输入! 请输入一个数字: sdfd 您输入的不是数字,请再次尝试输入! 请输入一个数字: Traceback (most recent call last): File "", line 3, in x = int(input("请输入一个数字: ")) KeyboardInterrupt

  • 多个except
    模块 sys中,有两个方法可以返回异常的全部信息,分别是 exc_info() 和 last_traceback(),这两个函数有相同的功能和用法。
    exc_info()方法会将当前的异常信息以元组的形式返回,该元组中包含 3 个元素,分别为 type、value 和 traceback,它们的含义分别是:
    (1)type:异常类型的名称,它是 BaseException 的子类。
    (2)value:捕获到的异常实例。
    (3)traceback:是一个 traceback 对象。
import sys try: f = open('myfile.txt')# open()函数用来打开文件myfile.txt s = f.readline()# f.readline()用来读取f的第一行整行内容,包括 "\n" 字符。 i = int(s.strip())# strip()方法用于移除字符串头尾指定的字符(默认为空格)或字符序列。 except OSError as err:# 如果myfile.txt文件没有创建,则会引发OSError异常 print("OS error: {0}".format(err)) except ValueError:# 如果s不是数字或者数字字符串,则int()转换失败,引发ValueError异常 print("Could not convert data to an integer.") except:# 在except后面不加任何的内容,则表示获取所有的异常 print("Unexpected error:", sys.exc_info()[0]) raise

  • try/except…else 语句
    except之后可以添加一个可选的else子句,如果要使用该子句,则需要把else子句放在所有except子句之后。
    使用 else 子句比把所有的语句都放在 try 子句里面要好,这样做的好处是可以避免一些意想不到而except又无法获取的异常。
    异常处理不仅仅可以处理那些发生在try子句中的异常,也可以处理子句中调用(包括间接调用的函数,即在一个函数中调用另一个函数)里抛出的异常。
def division_error(): x=10/0 #直接调用 try: division_error() except ZeroDivisionError as zero_er: print('error:',zero_er)def fn(): division_error() # 间接调用 try: fn() except ZeroDivisionError as zero_er: print('error:',zero_er)

  • try-finally语句:无论是否发生异常都将执行最后的代码。
try: print(a) except NameError: print(NameError) else: try: with open('myfile.txt') as mf: read_data = https://www.it610.com/article/mf.read() except FileNotFoundError as fnf_error: print(fnf_error) finally: print('无论异常是否发生,都会执行该代码。')

执行结果:
无论异常是否发生,都会执行该代码。

2.3 抛出异常
  • Python 使用 raise 语句抛出一个指定的异常,语法:raise [Exception [, args [, traceback]]]
  • raise 唯一的一个参数指定了要被抛出的异常,它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。
  • raise 的作用是有时我们只想知道是否有异常抛出,而不想去处理它,那么使用raise语句就可以再次抛出它。
try: raise NameError('aa') except NameError: print('一个异常被抛出') raise

执行结果:
一个异常被抛出 Traceback (most recent call last): File "D:/错误和异常.py", line 164, in raise NameError('aa') NameError: aa

扩展:自定义异常
我们知道异常其实是一个类,而所有异常类的父类是Exception类,因此我们通过继承来创建一个属于自己的异常类。

    推荐阅读