287 lines
9.2 KiB
Markdown
287 lines
9.2 KiB
Markdown
# 异常和错误
|
||
|
||
## 语法错误
|
||
|
||
python 解释器的语法检测不通过,必须在程序执行前就改正。
|
||
|
||
```python
|
||
#语法错误示范一
|
||
if
|
||
|
||
#语法错误示范二
|
||
def test:
|
||
pass
|
||
|
||
#语法错误示范三
|
||
print(haha
|
||
```
|
||
|
||
## 逻辑错误
|
||
|
||
```python
|
||
#用户输入不完整(比如输入为空)或者输入非法(输入不是数字)
|
||
num=input(">>: ")
|
||
res1 = int(num)
|
||
|
||
#无法完成计算
|
||
res1=1/0
|
||
res2=1+'str'
|
||
```
|
||
|
||
## 异常
|
||
|
||
异常就是程序运行时发生错误的信号,然后程序异常退出。
|
||
|
||

|
||
|
||
## 异常种类
|
||
|
||
在 python 中不同的异常可以用不同的类型(类)去标识,不同的类对象标识不同的异常,一个异常标识一种错误。
|
||
|
||
```python
|
||
# 触发IndexError
|
||
l=['eagle','aa']
|
||
l[3]
|
||
|
||
# 触发KeyError
|
||
dic={'name':'eagle'}
|
||
dic['age']
|
||
|
||
# 触发ValueError
|
||
s='hello'
|
||
int(s)
|
||
```
|
||
|
||
**常见异常**
|
||
|
||
| 异常类型 | 说明 |
|
||
| :---------------- | :----------------------------------------------------------- |
|
||
| AttributeError | 试图访问一个对象没有的属性,比如 foo.x,但是 foo 没有属性 x |
|
||
| IOError | 输入/输出异常;基本上是无法打开文件 |
|
||
| ImportError | 无法引入模块或包;基本上是路径问题或名称错误 |
|
||
| IndentationError | 语法错误(的子类) ;代码没有正确对齐 |
|
||
| IndexError | 下标索引超出序列边界,比如当x只有三个元素,却试图访问 x[5] |
|
||
| KeyError | 试图访问字典里不存在的键 |
|
||
| KeyboardInterrupt | Ctrl + C 被按下 |
|
||
| NameError | 使用一个还未被赋予对象的变量 |
|
||
| SyntaxError | Python 代码非法,代码不能编译 |
|
||
| TypeError | 传入对象类型与要求的不符合 |
|
||
| UnboundLocalError | 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它 |
|
||
| ValueError | 传入一个调用者不期望的值,即使值的类型是正确的 |
|
||
|
||
|
||
**其他异常**
|
||
|
||
| 异常类型 | 说明 | 常见使用场景 |
|
||
|:--|:--|:--|
|
||
| ArithmeticError | 所有数值计算错误的基类 | 数学运算出现异常时的通用捕获 |
|
||
| AssertionError | 断言语句(assert)失败 | 程序内部的条件检查失败时 |
|
||
| AttributeError | 尝试访问对象不存在的属性 | 使用未定义的对象属性或方法时 |
|
||
| BaseException | 所有内置异常的基类 | 通常不直接使用,用于自定义异常继承 |
|
||
| BufferError | 与缓冲区相关的操作错误 | 在使用缓冲区对象时出现错误 |
|
||
| BytesWarning | 字节相关的警告 | 字节操作的潜在问题警告 |
|
||
| DeprecationWarning | 关于使用已弃用功能的警告 | 使用即将被移除的特性时 |
|
||
| EnvironmentError | 操作系统错误的基类 | 系统相关操作异常的通用捕获 |
|
||
| EOFError | 到达文件末尾,无法读取 | 文件读取操作遇到意外的EOF |
|
||
| Exception | 常规错误的基类 | 捕获所有非系统退出的异常 |
|
||
| FloatingPointError | 浮点计算错误 | 浮点数运算出现特殊情况 |
|
||
| FutureWarning | 关于未来特性改变的警告 | 代码可能在未来版本不兼容 |
|
||
| GeneratorExit | 生成器被关闭 | 生成器的 close() 方法被调用 |
|
||
| ImportError | 导入模块失败 | 模块导入路径错误或模块不存在 |
|
||
| ImportWarning | 导入模块时的警告 | 模块导入可能存在问题 |
|
||
| IndentationError | 缩进错误 | Python 代码缩进不正确 |
|
||
| IndexError | 序列中没有此索引 | 访问列表等序列的越界索引 |
|
||
| IOError | 输入/输出操作失败 | 文件操作、网络请求等 IO 操作失败 |
|
||
| KeyboardInterrupt | 用户中断执行 | 程序被 Ctrl+C 中断 |
|
||
| KeyError | 映射中没有这个键 | 字典中不存在的键访问 |
|
||
| MemoryError | 内存溢出 | 程序耗尽可用内存 |
|
||
| NameError | 未声明/初始化对象 | 使用未定义的变量 |
|
||
| NotImplementedError | 尚未实现的方法 | 抽象基类方法需要子类实现 |
|
||
| OSError | 操作系统相关的错误 | 文件权限、系统调用等错误 |
|
||
| OverflowError | 数值运算超出最大限制 | 数值计算结果超出表示范围 |
|
||
| ReferenceError | 弱引用试图访问已经垃圾回收了的对象 | 使用弱引用时的对象访问 |
|
||
| RuntimeError | 一般的运行时错误 | 不适合其他类别的运行时错误 |
|
||
| RuntimeWarning | 可疑的运行时行为警告 | 运行时可能存在的问题警告 |
|
||
| StopIteration | 迭代器没有更多的值 | 迭代器遍历完成 |
|
||
| SyntaxError | Python 语法错误 | 代码语法错误,无法编译 |
|
||
| SyntaxWarning | 可疑的语法警告 | 语法虽然正确但可能存在问题 |
|
||
| SystemError | 一般的解释器系统错误 | Python 解释器内部错误 |
|
||
| SystemExit | 解释器请求退出 | 调用 `sys.exit()` 请求退出程序 |
|
||
| TabError | Tab和空格混用 | 混合使用 Tab 和空格导致的错误 |
|
||
| TypeError | 对类型无效的操作 | 操作或函数应用于不适当类型 |
|
||
| UnboundLocalError | 访问未初始化的本地变量 | 在赋值前引用局部变量 |
|
||
| UnicodeError | Unicode 相关的错误 | Unicode编码/解码错误的基类 |
|
||
| UnicodeDecodeError | Unicode 解码错误 | 无法将字节解码为 Unicode |
|
||
| UnicodeEncodeError | Unicode 编码错误 | 无法将 Unicode 编码为字节 |
|
||
| UnicodeTranslateError | Unicode 转换错误 | Unicode 转换过程中的错误 |
|
||
| UnicodeWarning | Unicode 相关警告 | Unicode 操作的潜在问题警告 |
|
||
| UserWarning | 用户代码生成的警告 | 用户自定义的警告信息 |
|
||
| ValueError | 传入无效的参数 | 值虽然类型正确但不合适 |
|
||
| Warning | 警告的基类 | 所有警告类型的基类 |
|
||
| ZeroDivisionError | 除数为零 | 数值除以零或取模零
|
||
|
||
|
||
# 异常处理
|
||
|
||
- python 解释器检测到错误,触发异常(也允许程序员自己触发异常)
|
||
- 程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)
|
||
- 如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理
|
||
- 异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正
|
||
|
||
```python
|
||
# 错误写法:
|
||
num1 = input('>>: ')
|
||
if num1.isdigit():
|
||
int(num1)
|
||
elif num1.isspace():
|
||
print('输入的是空格,就执行我这里的逻辑')
|
||
elif len(num1) == 0:
|
||
print('输入的是空,就执行我这里的逻辑')
|
||
else:
|
||
print('其他情情况,执行我这里的逻辑')
|
||
|
||
'''
|
||
问题:
|
||
1. 使用 if 的方式我们只为第一段代码加上了异常处理,但这些 if,跟你的代码逻辑并无关系,这样你的代码会因为可读性差而不容易被看懂
|
||
2. 这只是我们代码中的一个小逻辑,如果类似的逻辑多,那么每一次都需要判断这些内容,就会我们的代码特别冗长。
|
||
'''
|
||
|
||
# 正确写法:
|
||
try:
|
||
num = input("<<:")
|
||
int(num)
|
||
except:
|
||
print('你输入的是非数字')
|
||
finally:
|
||
print('程序结束')
|
||
```
|
||
|
||
## 基本语法
|
||
|
||
```python
|
||
try:
|
||
被检测的代码块
|
||
except 异常类型:
|
||
try 被检测的代码块,就执行这个位置的逻辑
|
||
...
|
||
else:
|
||
正常执行逻辑
|
||
finally:
|
||
扫尾工作
|
||
|
||
```
|
||
|
||
## 常见示例
|
||
|
||
**示例**:处理迭代器获取时 `StopIteration` 异常
|
||
|
||
```python
|
||
iterator01 = ( i** 2 for i in range(3) )
|
||
|
||
while True:
|
||
try:
|
||
print(iterator01.__next__())
|
||
except StopIteration as e:
|
||
print(e)
|
||
break
|
||
```
|
||
|
||
**示例**:处理数据类型转换时 `ValueError` 异常
|
||
|
||
```python
|
||
s1 = 'hello'
|
||
try:
|
||
int(s1)
|
||
except ValueError as e:
|
||
print(e)
|
||
|
||
# Output:
|
||
invalid literal for int() with base 10: 'hello'
|
||
```
|
||
|
||
**示例**:多分支异常处理
|
||
|
||
```python
|
||
s1 = 'hello'
|
||
try:
|
||
int(s1)
|
||
except IndexError as e:
|
||
print(e)
|
||
except KeyError as e:
|
||
print(e)
|
||
except ValueError as e:
|
||
print(e)
|
||
```
|
||
|
||
**Exception**
|
||
|
||
```python
|
||
s1 = 'hello'
|
||
try:
|
||
int(s1)
|
||
except Exception as e:
|
||
print(e)
|
||
```
|
||
|
||
多分支加万能异常
|
||
|
||
```python
|
||
s1 = 'hello'
|
||
try:
|
||
int(s1)
|
||
except IndexError as e:
|
||
print(e)
|
||
except KeyError as e:
|
||
print(e)
|
||
except ValueError as e:
|
||
print(e)
|
||
except Exception as e:
|
||
print(e)
|
||
```
|
||
|
||
**其他异常情况**
|
||
|
||
```python
|
||
s1 = '10'
|
||
try:
|
||
int(s1)
|
||
except IndexError as e:
|
||
print(e)
|
||
except KeyError as e:
|
||
print(e)
|
||
except ValueError as e:
|
||
print(e)
|
||
except Exception as e:
|
||
print(e)
|
||
else:
|
||
print('try内代码块没有异常则执行我')
|
||
finally:
|
||
print('无论异常与否,都会执行该模块,通常是进行清理工作')
|
||
```
|
||
|
||
## 主动触发异常
|
||
|
||
```python
|
||
try:
|
||
raise TypeError('类型错误')
|
||
except Exception as e:
|
||
print(e)
|
||
```
|
||
|
||
## 自定义异常
|
||
|
||
```python
|
||
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)
|
||
```
|
||
|
||
**总结**:代码更健壮,更易组织,更清晰。
|