1.介绍
异常在程序中无处不在,也无法避免,如果不妥善处理潜在的异常,可能会导致整个程序的退出,在Python
中使用try...except
来捕获异常,从而避免程序退出或者不能正常运行。
1.1 不捕获示例
# --------------代码部分----------------
def demo(a: int, b: int) -> float:
return a / b
if __name__ == "__main__":
# 不捕获异常示例
res = demo(10, 0)
print("res = ",res)
# --------------输出----------------
Traceback (most recent call last):
File "D:\wwwroot\python\test\main.py", line 10, in <module>
res = demo(10, 0)
^^^^^^^^^^^
File "D:\wwwroot\python\test\main.py", line 5, in demo
return a / b
~~^~~
ZeroDivisionError: division by zero
1.2 捕获示例
# --------------代码部分----------------
def demo(a: int, b: int) -> float:
return a / b
if __name__ == "__main__":
# 捕获异常示例
try:
res = demo(10, 0)
except ZeroDivisionError:
res = None
print("不能除以0")
print("res = ", res)
# --------------输出----------------
不能除以0
res = None
2. 捕获语法
2.1 常见语法
Python
支持多种组合方式捕获异常,一般我们常见的捕获语法如下:
try:
# 代码逻辑...
except 异常对象:
# 对异常进行处理...
2.2 常见内置异常对象
异常对象 | 说明 |
---|---|
Exception |
通用错误,一般都能用 |
AttributeError |
访问某个对象不存在的属性时 |
FileNotFoundError |
文件不存在 |
IndexError |
索引超过范围错误 |
KeyError |
访问字典中不存在的key
|
ZeroDivisionError |
除数为0错误 |
NameError |
访问的变量未曾定义 |
TypeError |
数据类型错误 |
SyntaxError |
代码语法错误 |
3.捕获异常方式
3.1 try..except
这种方式是最基本的捕获方式,最开始部分已经演示,这里直接跳过。
3.2 加个 else
3.2.1 捕获语法
try:
# 代码逻辑...
except 异常对象:
# 对异常进行处理...
else:
# 代码不发生异常处理...
3.2.2 代码示例
# ------------------- 代码 -------------------
if __name__ == "__main__":
try:
res = demo(10, 2)
except ZeroDivisionError:
res = None
print("不能除以0:")
else:
print("代码运行正常")
print("res = ", res)
# ------------------- 输出 -------------------
# 代码运行正常
# res = 5.0
@示例中的
demo
函数参见上个示例,这里不在重复.
3.3 多个except
当我们的程序复杂以后,可能会出现各种错误,不一定哪种错误先触发,这个时候我们就需使用多个except
去捕获
3.3.1 捕获语法
try:
# 代码逻辑...
except 异常对象A:
# 对异常进行处理...
except 异常对象B:
# 对异常进行处理..
except 异常对象C:
# 对异常进行处理..
3.3.2 代码示例
if __name__ == "__main__":
try:
print("具体代码逻辑.....")
except KeyError:
print("key不存在")
except FileNotFoundError:
print("文件不存在")
except Exception:
print("未知错误")
print("运行完成")
@注:捕获多个异常,也可以使用一个except,如except(异常对象A,异常对象B,…):
3.4 加个finally
3.4.1 捕获语法
try:
# 代码逻辑...
except 异常对象A:
# 对异常进行处理...
finally:
# 不管是否异常都要运行的部分
3.4.2 代码示例
# ------------------- 代码 -------------------
if __name__ == "__main__":
# noinspection PyBroadException
try:
print("打开文件,读取内容..")
demo(1, 0)
except Exception as e:
# 打印错误信息
print("发生未知错误: " + str(e))
finally:
print("关闭文件")
print("运行结束")
# ------------------- 输出 -------------------
# 打开文件,读取内容..
# 发生未知错误: division by zero
# 关闭文件
# 运行结束
4. 抛出异常方式
在开发过程中不但要捕获异常,有时也需要我们主动抛出异常,在Python
中,使用关键字raise
抛出异常,语法如下:
raise 异常对象("这里写错误信息..")
4.1 抛出内置错误
# -------------------代码 -----------------------
def demo(a: int, b: int) -> float:
if b == 0:
# 抛出异常
raise Exception("参数错误,分母不能为0~")
return a / b
if __name__ == "__main__":
# noinspection PyBroadException
try:
demo(1, 0)
except Exception as e:
# 打印错误信息
print("运行异常: " + str(e))
print("运行结束")
# -------------------输出 -----------------------
# 运行异常: 参数错误,分母不能为0~
# 运行结束
4.2 抛出自定义错误
在实际开发过程中,有时我们需要抛出自定义的错误,用来和内置错误进行区分,示例代码如下:
# ------------------- 自定义错误 -----------------------
# 自定义错误,继承父类
class MyError(Exception):
pass
# ------------------- 修改上面示例 -----------------------
def demo(a: int, b: int) -> float:
if b == 0:
# 抛出异常
raise MyError("参数错误,分母不能为0~")
return a / b
if __name__ == "__main__":
# noinspection PyBroadException
try:
demo(1, 0)
except MyError as e:
# 打印错误信息
print("运行异常: " + str(e))
print("运行结束")
# -------------------输出 -----------------------
# 运行异常: 参数错误,分母不能为0~
# 运行结束
5. 具体错误位置
有时候虽然我们捕获了异常,但是却不能准确的定位到具体哪一行代码,Python
提供了traceback
包,用来解决这个问题。
5.1 使用示例
# -------------------文件: basis/error.py -----------------------
from common import demo
def testError(a: int, b: int) -> float:
print("运行到testError;a :{} b:{}".format(a, b))
add = a + a
return demo.divide(add, b)
# -------------------文件: common/demo.py -----------------------
def divide(a: int, b: int) -> float:
print("运行到divide;a :{} b:{}".format(a, b))
if b == 0:
# 抛出异常
raise Exception("参数错误,分母不能为0~")
return a / b
# --------------------------main.py ------------------------------
import traceback
from basis import error
if __name__ == "__main__":
# noinspection PyBroadException
try:
r = error.testError(10, 0)
print(r)
except Exception as e:
# 打印错误信息
print("运行异常: ", traceback.format_exc())
print("运行结束")
# --------------------------输出 ------------------------------
运行到testError;a :10 b:0
运行到divide;a :20 b:0
运行异常: Traceback (most recent call last):
File "D:\wwwroot\python\test\main.py", line 8, in <module>
r = error.testError(10, 0)
^^^^^^^^^^^^^^^^^^^^^^
File "D:\wwwroot\python\test\basis\error.py", line 15, in testError
return demo.divide(add, b)
^^^^^^^^^^^^^^^^^^^
File "D:\wwwroot\python\test\common\demo.py", line 15, in divide
raise Exception("参数错误,分母不能为0~")
Exception: 参数错误,分母不能为0~
6.异常层次结构解析
BaseException # 所有异常的基类
+-- SystemExit # 解释器请求退出
+-- KeyboardInterrupt # 用户中断执行(通常是输入^C)
+-- GeneratorExit # 生成器(generator)发生异常来通知退出
+-- Exception # 常规异常的基类
+-- StopIteration # 迭代器没有更多的值
+-- StopAsyncIteration # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
+-- ArithmeticError # 各种算术错误引发的内置异常的基类
| +-- FloatingPointError # 浮点计算错误
| +-- OverflowError # 数值运算结果太大无法表示
| +-- ZeroDivisionError # 除(或取模)零 (所有数据类型)
+-- AssertionError # 当assert语句失败时引发
+-- AttributeError # 属性引用或赋值失败
+-- BufferError # 无法执行与缓冲区相关的操作时引发
+-- EOFError # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
+-- ImportError # 导入模块/对象失败
| +-- ModuleNotFoundError # 无法找到模块或在在sys.modules中找到None
+-- LookupError # 映射或序列上使用的键或索引无效时引发的异常的基类
| +-- IndexError # 序列中没有此索引(index)
| +-- KeyError # 映射中没有这个键
+-- MemoryError # 内存溢出错误(对于Python 解释器不是致命的)
+-- NameError # 未声明/初始化对象 (没有属性)
| +-- UnboundLocalError # 访问未初始化的本地变量
+-- OSError # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
| +-- BlockingIOError # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
| +-- ChildProcessError # 在子进程上的操作失败
| +-- ConnectionError # 与连接相关的异常的基类
| | +-- BrokenPipeError # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
| | +-- ConnectionAbortedError # 连接尝试被对等方中止
| | +-- ConnectionRefusedError # 连接尝试被对等方拒绝
| | +-- ConnectionResetError # 连接由对等方重置
| +-- FileExistsError # 创建已存在的文件或目录
| +-- FileNotFoundError # 请求不存在的文件或目录
| +-- InterruptedError # 系统调用被输入信号中断
| +-- IsADirectoryError # 在目录上请求文件操作(例如 os.remove())
| +-- NotADirectoryError # 在不是目录的事物上请求目录操作(例如 os.listdir())
| +-- PermissionError # 尝试在没有足够访问权限的情况下运行操作
| +-- ProcessLookupError # 给定进程不存在
| +-- TimeoutError # 系统函数在系统级别超时
+-- ReferenceError # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
+-- RuntimeError # 在检测到不属于任何其他类别的错误时触发
| +-- NotImplementedError # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
| +-- RecursionError # 解释器检测到超出最大递归深度
+-- SyntaxError # Python 语法错误
| +-- IndentationError # 缩进错误
| +-- TabError # Tab和空格混用
+-- SystemError # 解释器发现内部错误
+-- TypeError # 操作或函数应用于不适当类型的对象
+-- ValueError # 操作或函数接收到具有正确类型但值不合适的参数
| +-- UnicodeError # 发生与Unicode相关的编码或解码错误
| +-- UnicodeDecodeError # Unicode解码错误
| +-- UnicodeEncodeError # Unicode编码错误
| +-- UnicodeTranslateError # Unicode转码错误
+-- Warning # 警告的基类
+-- DeprecationWarning # 有关已弃用功能的警告的基类
+-- PendingDeprecationWarning # 有关不推荐使用功能的警告的基类
+-- RuntimeWarning # 有关可疑的运行时行为的警告的基类
+-- SyntaxWarning # 关于可疑语法警告的基类
+-- UserWarning # 用户代码生成警告的基类
+-- FutureWarning # 有关已弃用功能的警告的基类
+-- ImportWarning # 关于模块导入时可能出错的警告的基类
+-- UnicodeWarning # 与Unicode相关的警告的基类
+-- BytesWarning # 与bytes和bytearray相关的警告的基类
+-- ResourceWarning # 与资源使用相关的警告的基类。被默认警告过滤器忽略。
网友评论