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:
- 预备方案1
- except 异常类型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 range
- 56
- """
 
 
- 值得注意的是,写在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中的语句。
```python
s = ""
for i in "ABC":
s += i.lower()
else:
print(s)
"""
程序运行结果:abc
"""
i = 15
while i >= 10:
i -= 1
if i == 12:
break
else:
print(i)
"""
没有运行结果:程序是被break中止的,并非正常退出的,故else不执行。
"""
- 当else运用到try-except中时,是指try中的所有语句没有出现异常时,执行else中的语句。 - try:
- num1 = 10
- num2 = 20
- num3 = num1 + num2
- except Exception as e:
- print(e)
- else:
- print(num3)
- """
- 运行结果:30
- try中的语句没有出现任何异常
- 故执行else中的print(num3)语句
- """
 
- 示例:输入一个整数,求它和10的差,只要录入的不是整数,就要一直录入下去,直到是整数为止,然后输出计算结果。 - while True:
- try:
- num = int(input("请输入一个整数:"))
- except ValueError as e:
- print(e)
- else:
- result = num - 10
- print(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过大`。
```python
num = int(input("输入一个数字:"))
if num >= 100:
raise ValueError(f"{num=}过大")
 
 
                         
                                

