Python学习(八):异常处理

84 阅读5分钟

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 "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/main.py", line 10, in <module>
    res = demo(10, 0)
          ^^^^^^^^^^^
  File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/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 "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/main.py", line 8, in <module>
    r = error.testError(10, 0)
        ^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/basis/error.py", line 15, in testError
    return demo.divide(add, b)
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/liuqh/ProjectItem/PythonItem/python-learn-demo/common/demo.py", line 15, in divide
    raise Exception("参数错误,分母不能为0~")
Exception: 参数错误,分母不能为0~

微信搜索【猿码记】查看更多文章

本文由mdnice多平台发布