一步一步展示并总结Python的异常

简介: 正式的Python专栏第17篇,同学站住,别错过这个从0开始的文章!

写程序,写多了,就容易出bug,当然也容易出现Exception异常!


什么是错误与异常Exception?

这个跟语法错误不一样,语法错误编译器会直接提示处理(在程序运行之前)。 比如IndentationError,这种是语法级别的异常,它也是Exception的子类)


出bug,则是在运行过程中产生超乎意料的处理结果,逻辑处理错误,但是这类错误通常不会让程序中断,往往是反应在最后的结果输出中,发现偶然几次运行跟预期的不一样,或者偶然几个输入的输出结果不符合总体运行规律。


异常就是程序中间出现 值/操作 不在系统内设定预期值内,在程序执行过程中产生的错误(不合法的数据类型,超预期设定的像磁盘/网络/文件故障等等),而且错误会被程序抛出,中止后续运行。 所以有时候我们也称呼异常为:运行时错误!


可能小白不太懂,比如下面一个现象,有点高能:


小白打算申请跟Python编译器登记结婚? 无法理解的,称之为错误!

小白跟一个萌妹子结婚,这是正常情况(没有异常也没有错误)

小白跟一个同性结婚,这是属于异常情况(在现今社会没有被广泛认可,但是确实存在。)


大概的意思就是,编程里面也是存在‘标签化’的语义。


异常 和 错误 本身就是超越常规程序运行应该处理的结果,我们习惯与把一些表现归类为错误,习惯与另一部分归类为异常。


文末会展示异常的结构树,会再次谈到异常跟错误的关系。


展示一下异常

直接复制下方代码到python REPL终端:


result = 1 / 0
print("result=", result)

运行效果如下:

image.png

看到了吗?


这就是异常,这里的异常是:ZeroDivisionError, 错误消息:division by zero(除零错误!)


错误与异常的关联和更多展示

常见的异常很多,像下面的几种,都非常常见。


ModuleNotFoundError : 通常出现在import leixuewei #导入一个库的时候,这个库不存在则抛出异常!

KeyError: 出席在dict类型的数据取某个键值的时候,比如直接定义一个dict类型的数据,不放入任何键值就取‘leixuewei’这个key,那就会抛出这个错误。

IndexError: 这种就是访问数组或者list列表数据的时候,超出下标,明明一个list就只有2个元素,硬要取第三个元素的时候报错。

ArithmeticError: 上面展示的数值除以0,抛出的异常就是一种,还包括了OeverflowError, FloatingPointError等。

这些错误都非常直观。


这里我们可以打开PyCharm找到Exception类,使用‘find usage’ 查看这个类的子类。


image.png

记住这些异常,其实意义不大。

我们编程更多是需要知道异常的链条和如何使用异常,知道把握这些异常的关联: 继承关系。

下面,我们双击RuntimeError, 马上就发现这个RuntimeError class 后面紧跟了一个NotImplementedError子类。

image.png

那么异常的根源在哪里?

我们继续查找Exception 的父亲BaseException,如下图:

image.png

开发中如何运用异常

灵活运用断言异常,它就挺适合在程序中进行预判的。当然最好的方式是,补充unittest(单元测试)这个在学委之前文章中提到了。

AssertionError 断言异常

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/23 12:32 下午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : assertdemo.py
# @Project : hello
def double(v1):
    result = v1 * 2
    assert result == v1 + v1
    return result
def double_v2(v1):
    result = v1 * 2
    assert result == v1 + 2
    return result
print(double(3))
print(double_v2(3))

运行效果如下:

image.png

这里我们写了一个double(双倍函数),出入一个数字,内部计算应该是2*数字,我们也预期结果为: 数字 + 数字


这种断言异常可以在程序中灵活使用,学委建议不要一下子写几百行代码,而且实现一段逻辑代码的时候适当加上。


比如在做算法类型的题目的时候,加上这个可以有效的辅助程序的完成:有效的中间产生结果校验。


异常处理

Python 提供了语法支持方便我们针对程序异常,按情况进行处理,语法解释如下:


try:
    #运行可能出现异常的函数abc
    abc()
except Exception as e:
    #上述函数abc运行出现异常
    运行一下异常补救的代码或者记录异常
else:
  #abc函数没有发生异常
  运行确认没有异常的代码
finally:
    #不管有没有异常
    print(“总会被执行打印!”)

这里学委写了一段示例代码,可以直接复制运行:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/24 1:54 下午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : trycatchdemo.py
# @Project : hello
def divide(a, b):
    return a / b
result = 100
has_error = False
try:
    data = divide(1, 0) #运行除0函数,会抛出异常
except Exception as e:
    print("error is %s" % e)
    has_error = True
else:
    print("there is no exception")
finally:
    print("always run ")
if not has_error:
    result += data
print("final value %s" % result)

异常捕捉,可以让程序跳过指定异常,继续执行。

如语法介绍那样,正确运行如下图:

image.png

使用try-except语句这不是必要的。


通常我们在应对外部接口或者外部程序调用,外部资源整合的时候,用这个可以有效的保护本程序,跳过外部(别人的)程序错误,继续执行程序,仅此而已。


可以在except 块内放置一些错误处理或者补救代码,比如divide函数还成对等的函数,然后继续后续程序处理。


定义自己的异常,并抛出!

当我们开发一个大型应用的时候,比如Django,我们发现运行这个框架开发的时候,有时候会出现一写Django自带的异常。


这种要如何做?


定义用户自己的异常

通常都是继承RuntimeError类,这类型的异常肯定是运行时异常。


如下:


#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/10/24 2:18 下午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : userexception.py
# @Project : hello
class DotNotCopyError(RuntimeError):
    def __init__(self, arg):
        self.args = arg
def copy():
    print("抄袭!")
    raise DotNotCopyError("某某抄袭了学委的文章!")
copy()

非常简单,这里也展示了如何抛出异常,我们使用raise关键字加上异常的实例即可。

运行效果如下:

image.png

raise也可以抛出其他内置的异常,可以根据需要在程序中使用。比如程序中检测网络情况,预先抛出异常,帮助运维及早发现外部依赖故障。这个请根据实际情况编写。

延伸思考 - SyntaxError居然也是异常的子类!

image.png

但是这里我们看到SyntaxError也是异常Exception,错误不是跟异常不一样吗?怎么都是同个父亲:Exception。所以严格上来说或Exception不能称为运行时异常,而是部分Exception的子类为运行时异常,因为SyntaxError属于编译解析器解析代码的时候发现的语法错误。


而且SyntaxError是不能够被程序捕捉的。


从这里看,Python的异常机制设计跟Java相比显得比较凌乱了!在Java中异常的根部是Throwable,然后延伸出Error和Exception两个派系,像Error是不能被捕捉,这方面比较清晰。


总结

python的异常,学委总结如下:


image.png

今天1024,学委在此祝愿大家程序不出bug,然后拿捏一切异常!

目录
相关文章
|
3月前
|
Python
Python学习 -- 异常堆栈追踪技术
Python学习 -- 异常堆栈追踪技术
28 0
|
3月前
|
Python
Python学习 -- 异常捕获技巧
Python学习 -- 异常捕获技巧
20 0
|
1月前
|
开发者 UED Python
怎么理解python中的错误和异常
怎么理解python中的错误和异常
25 0
|
10天前
|
Python
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
52 0
|
18天前
|
开发者 Python
使用python打印异常
Python的try-except用于异常处理,尝试执行try块中的代码,若出现异常,则由except捕获并处理。示例展示了当尝试除以零引发`ZeroDivisionError`时,如何打印异常信息。使用`traceback`模块可获取更详尽的异常堆栈信息。在实际应用中,异常信息应根据需求写入日志或发送给开发者,避免向用户暴露敏感信息。
11 0
|
23天前
|
Python
Python中异常的抛出与捕获
4月更文挑战第3天,Python中的异常是处理错误的方式,当错误发生时,异常被触发,未被捕获则导致程序终止。通过`raise`可手动抛出异常,例如`raise ValueError("Invalid value provided")`或自定义异常。使用`try-except`捕获异常,避免程序意外结束。`try`块包含可能出错的代码,`except`块处理特定异常,`else`子句在无异常时执行,`finally`子句确保清理代码始终执行。
17 2
Python中异常的抛出与捕获
|
1月前
|
Python
在Python中文件异常
在Python中文件异常
13 1