01. Python异常机制
1.1 异常的概念
1.1.1 语法错误
- 语法错误又称为解析错误,是学习Python时最常见的错误。
- 在IDE中,这类错误会被标记出来:

- 在程序运行时,Python解释器会复现错误的代码行,并用小箭头
^指向行里检测到的第一个错误。- 如下图中,在
print("Hello World")的p下方出现了小箭头。 - 说明在p前后出现了语法错误(这里就是
while True语句后缺少了冒号:与缩进)。
- 如下图中,在
1.1.2 异常
- 即使语句或表达式使用了正确的语法,执行时仍可能触发错误。
- 执行时检测到的错误称为异常,异常会导致程序运行终止,并且解释器会报出错误信息。
```python
除数为0异常
10 * (1 / 0) Traceback (most recent call last): File “
“, line 1, in ZeroDivisionError: division by zero
标识符未定义异常
4 + spam * 3 Traceback (most recent call last): File “
“, line 1, in NameError: name ‘spam’ is not defined
类型计算异常
‘2’ + 2 Traceback (most recent call last): File “
“, line 1, in TypeError: can only concatenate str (not “int”) to str ``` 1.1.3 错误信息解读
- 对于整个报错信息而言,最有用的实际上是最后一行信息。
- 错误信息的最后一行说明程序遇到了什么类型的错误。
- 异常有不同的类型,而类型名称会作为错误信息的一部分中打印出来:ZeroDivisionError、NameError、TypeError、……。
- 作为异常类型打印的字符串是发生的内置异常的名称。
- 对于所有内置异常都是如此,但对于用户定义的异常则不一定如此(虽然这种规范很有用)。标准的异常类型是内置的标识符(不是保留关键字)。
-
1.2 Python异常体系与结构层次
大部分可见到的异常都是Exception的子类。
底部的Warning只是一个警告,不会报错,也不会终止程序的运行。
BaseException+-- SystemExit+-- KeyboardInterrupt+-- GeneratorExit+-- Exception+-- StopIteration+-- StopAsyncIteration+-- ArithmeticError| +-- FloatingPointError| +-- OverflowError| +-- ZeroDivisionError+-- AssertionError+-- AttributeError+-- BufferError+-- EOFError+-- ImportError| +-- ModuleNotFoundError+-- LookupError| +-- IndexError| +-- KeyError+-- MemoryError+-- NameError| +-- UnboundLocalError+-- OSError| +-- BlockingIOError| +-- ChildProcessError| +-- ConnectionError| | +-- BrokenPipeError| | +-- ConnectionAbortedError| | +-- ConnectionRefusedError| | +-- ConnectionResetError| +-- FileExistsError| +-- FileNotFoundError| +-- InterruptedError| +-- IsADirectoryError| +-- NotADirectoryError| +-- PermissionError| +-- ProcessLookupError| +-- TimeoutError+-- ReferenceError+-- RuntimeError| +-- NotImplementedError| +-- RecursionError+-- SyntaxError| +-- IndentationError| +-- TabError+-- SystemError+-- TypeError+-- ValueError| +-- UnicodeError| +-- UnicodeDecodeError| +-- UnicodeEncodeError| +-- UnicodeTranslateError+-- Warning+-- DeprecationWarning+-- PendingDeprecationWarning+-- RuntimeWarning+-- SyntaxWarning+-- UserWarning+-- FutureWarning+-- ImportWarning+-- UnicodeWarning+-- BytesWarning+-- ResourceWarning
02. 异常处理
2.1 异常处理的基本概念
2.1.1 Python异常处理介绍
所谓异常处理,不是说把这个异常捕获到了,然后去改正这个错误,而是如果程序运行过程中出现了这个错误,Python程序需要用怎样的预备方案去应对。
比如一家发电厂因为一些原因停止发电了(程序运行出现异常导致程序运行中止),但是为了给负责的区域内供电保证正常的运行,发电厂一般都会有备用发电机,当主要发电机不工作时,可以采用备用发电机正常进行发电工作,这就类似于程序中的异常处理。
2.1.2 Python异常处理流程
Python解释器在正常情况下会逐行解释并执行相应的程序代码。
- 但是在执行过程中,如果遇到了错误,就会抛出这个错误对应的异常对象。
接着Python解释器会检测该异常是否被特定的结构所捕获。
Python中捕获异常有三种格式:
try-except、try-except-finally、try-except-else。2.2.1 try-except捕获异常
try-except异常捕获的语法格式:
try:可能出现异常的代码except 异常类型1 as 变量名1:预备方案1except 异常类型2 as 变量名2:预备方案2……except 异常类型n as 变量名n:预备方案n
示例:有一个长度为4的列表
nums = [19, 27, 33, 56],试图打印索引位4的元素会报错。nums = [19, 27, 33, 56]value = nums[4]print(value)"""运行报错:Traceback (most recent call last):File "D:\Project\Python\BaseProject\Day03\global_variable_test.py", line 9, in <module>value = nums[4]IndexError: list index out of range"""
- 此时,就可以捕获这个异常,并给出一个预备方法,如:若出现了下标越界异常,则打印这个列表最后一个元素。
try:nums = [19, 27, 33, 56]value = nums[4]except IndexError as err:print(err)value = nums[-1]print(value)"""运行结果:list index out of range56"""
值得注意的是,写在try中的代码,如果出现异常并被捕获,则异常之后的代码也不会被执行。
try:nums = [19, 27, 33, 56]value = nums[4] # 这里会出现异常ele = nums[0] # 这行代码不会被执行except IndexError as err:print(err)value = nums[-1]print(value)print(ele) # 报错:NameError: name 'ele' is not defined
2.2.2 try-except-finally捕获异常
try-except-finally应用场景:
- try-except-finally结构中的try-except与2.2.1中没有区别,finally一般用来让程序与外面资源切断联系。
- 比如,对数据库的操作,不管try-except是否捕捉到了异常,与数据库的连接都要关闭。
try-except-finally异常捕获的语法格式:
try:可能出现异常的代码except 异常类型 as 变量名:预备方案finally:不管是否出现异常都执行的操作
示例:用PyMySQL创建一个数据库连接,然后在这个过程中不管是否出现异常,数据库连接都应该被关闭。 ```python import pymysql
connect = None try:
# 简历数据库连接对象connect = pymysql.Connect(host='localhost',port=3306,user='root',password='123456',database='mysql_learning',charset='utf8mb4')print(connect)
except Exception as e: print(e) finally:
# 只要数据库连接不为空,那么不管try中的程序是否报错,connect都应该被关闭if connect is not None:connect.close()
<a name="NNTwQ"></a>#### 2.2.3 try-except-else捕获异常- else的运用位置概述:- 之前的else都是声明在`if-else`、`if-elif-else`语句中的,当if和elif中所有的条件判断语句都为False时,会执行else中的语句。- 此外,else还可以是`while-else`和`for-else`,当循环正常退出时(while循环的条件为False、for循环遍历完序列中所有元素时)就会执行else中的语句。```pythons = ""for i in "ABC":s += i.lower()else:print(s)"""程序运行结果:abc"""i = 15while i >= 10:i -= 1if i == 12:breakelse:print(i)"""没有运行结果:程序是被break中止的,并非正常退出的,故else不执行。"""
当else运用到try-except中时,是指try中的所有语句没有出现异常时,执行else中的语句。
try:num1 = 10num2 = 20num3 = num1 + num2except Exception as e:print(e)else:print(num3)"""运行结果:30try中的语句没有出现任何异常故执行else中的print(num3)语句"""
示例:输入一个整数,求它和10的差,只要录入的不是整数,就要一直录入下去,直到是整数为止,然后输出计算结果。
while True:try:num = int(input("请输入一个整数:"))except ValueError as e:print(e)else:result = num - 10print(f"{result=}")break
2.3 finally执行先于return
在函数中使用try-catch-finally结构时,finally的执行优先级会高于return语句。
- 示例:定义一个div函数,传入两个数,计算这两个数的商并写入到./result.txt文件中。若写入成功,则返回商,否则返回0。
```python
def div(num1, num2) -> int:
try:
except ZeroDivisionError as e:file = open("./result.txt", "w", encoding="utf-8")result = num1 / num2 # 当num2为0时,会出现ZeroDivisionError异常。file.write(f'{result}')return result
finally:print("分母num2的值不能为0")file.write(f"{0}")return 0
print("程序执行完成,文件result.txt将被关闭")file.close()
print(div(10, 2))
- 在第15行调用div函数处打断点,可以查看到整个函数的执行流程。- 可以发现,当try中的代码运行到第6行的`return result`时,会直接跳到finally中执行finally结构中的语句。- 当finally结构中的所有语句都执行完成后,会再跳回到第六行,然后将结果返回。- 以上说明finally的执行优先级先于return语句。<a name="KD51g"></a>## 03. 抛出异常- 抛出异常语法格式:`raise 异常类型(异常信息)`- 示例:输入一个整型数字,当这个数字大于100时,抛出ValueError异常,异常信息为`num=value过大`。```pythonnum = int(input("输入一个数字:"))if num >= 100:raise ValueError(f"{num=}过大")
