Python-异常处理

一、Python中常见的异常

异常描述
BaseException所有异常的基类
Exception常规错误的基类
NameError尝试访问一个没有声明的变量引发的错误
IndexError索引超出序列范围引起的错误
IndentationError缩进错误
ValueError传入无效的参数
KeyError使用映射中不存在的键引发的错误
IOError输入/输出操作错误
ImportError导入模块/对象失败
AttributeError对象没有这个属性引发的错误
TypeError类型不合适引发的错误
MemoryError内存溢出错误(对于Python 解释器不是致命的)
ZeroDivisionError除数为0引发的错误
AssertionError断言语句失败
SyntaxErrorPython 语法错误

二、异常处理语句

1. try…except语句

try 语句的工作原理如下:

  • 首先,执行 try 子句 (try 和 except 关键字之间的(多行)语句)。
  • 如果没有触发异常,则跳过 except 子句,try 语句执行完毕。
  • 如果在执行 try 子句时发生了异常,则跳过该子句中剩下的部分。 如果异常的类型与 except 关键字后指定的异常相匹配,则会执行 except 子句,然后跳到 try/except 代码块之后继续执行。
  • 如果发生的异常与 except 子句 中指定的异常不匹配,则它会被传递到外部的 try 语句中;如果没有找到处理程序,则它是一个 未处理异常 且执行将终止并输出如上所示的消息。
try:
     可能出现错误的代码块
except 异常类型:
     try中一旦检测到异常,就执行这个位置的逻辑

在使用try…except语句捕获异常时,如果在except后面不指定异常名称,则表示捕获全部异常。
1.单分支

try:
    ab
except NameError as e:  #我们可以使用except与as+变量名 搭配使用,打印变量名会直接输出报错信息
    print(e)   #name 'ab' is not defined

2.多分支

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except BaseException as err:
    print(f"Unexpected {err=}, {type(err)=}")

运行结果:

OS error: [Errno 2] No such file or directory: 'myfile.txt'

Process finished with exit code 0

try 语句可以有多个 except 子句 来为不同的异常指定处理程序。 但最多只有一个处理程序会被执行。 处理程序只处理对应的 try 子句 中发生的异常,而不处理同一 try 语句内其他处理程序中的异常。 except 子句 可以用带圆括号的元组来指定多个异常,例如:

import sys
try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except (ValueError,OSError,BaseException) as e:
    print(e)

运行结果:

[Errno 2] No such file or directory: 'myfile.txt'

Process finished with exit code 0

2. try…except…else语句

用于指定当try语句块中没有发现异常时要执行的语句;当try语句中发现异常时,else语句将不会被执行。

try:
    for i in range(10):
        int(i)
except IndexError as e:
    print(e)
else:
    print('***********')   #***********   执行了此处
    #当try语句中的代码没有异常,被完整地执行完,就执行else中的代码

'''
***********

Process finished with exit code 0
'''
try:
    b=10/0
except ZeroDivisionError as e:
    print(e)
else:
    print('***********')   #***********   执行了此处
    #当try语句中的代码没有异常,被完整地执行完,就执行else中的代码

'''
division by zero

Process finished with exit code 0
'''

3. try…except…finally语句

如果存在 finally 子句,则 finally 子句是 try 语句结束前执行的最后一项任务。不论 try 语句是否触发异常,都会执行 finally 子句。

  • 如果执行 try 子句期间触发了某个异常,则某个 except 子句应处理该异常。如果该异常没有 except 子句处理,在 finally 子句执行后会被重新触发。
  • except 或 else 子句执行期间也会触发异常。 同样,该异常会在 finally 子句执行之后被重新触发。
  • 如果 finally 子句中包含 break、continue 或 return 等语句,异常将不会被重新引发。
  • 如果执行 try 语句时遇到 break,、continue 或 return 语句,则 finally 子句在执行 break、continue 或 return 语句之前执行。
  • 如果 finally 子句中包含 return 语句,则返回值来自 finally 子句的某个 return 语句的返回值,而不是来自 try 子句的 return 语句的返回值。
>>> def bool_return():
...     try:
...         return True
...     finally:
...         return False
...
>>> bool_return()
False
>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

4. 使用raise语句抛出异常

try:
    raise TypeError('类型错误')
except Exception as e:
    print(e)
'''
类型错误

Process finished with exit code 0
'''

raise 唯一的参数就是要触发的异常。这个参数必须是异常实例或异常类(派生自 Exception 类)。如果传递的是异常类,将通过调用没有参数的构造函数来隐式实例化:

raise ValueError  # shorthand for 'raise ValueError()'

如果只想判断是否触发了异常,但并不打算处理该异常,则可以使用更简单的 raise 语句重新触发异常:

try:
    raise NameError('HiThere')
except NameError:
    print('An exception flew by!')
    raise

运行结果:

Traceback (most recent call last):
  File "E:/PC/untitled/练习/test.py", line 259, in <module>
    raise NameError('HiThere')
NameError: HiThere
An exception flew by!

Process finished with exit code 1

5.用户自定义异常

class EvaException(BaseException):
    def __init__(self,msg):
        self.msg=msg
    def __str__(self):
        return self.msg

try:
    raise EvaException('类型错误')
except EvaException as e:
    print(e)

6.断言

assert断言是声明其布尔值必须为真的判定,如果发生异常就说明表达示为假。可以理解assert断言语句为raise-if-not,用来测试表示式,其返回值为假,就会触发异常。

assert的异常参数,其实就是在断言表达式后添加字符串信息,用来解释断言并更好的知道是哪里出了问题。格式如下:
assert expression [, arguments]
assert 表达式 [, 参数]

assert isinstance('1.23',float)

运行结果:

    assert isinstance('1.23',float)
AssertionError

Process finished with exit code 1

7.异常链

参考官方文档:https://docs.python.org/zh-cn/3/tutorial/errors.html