写点什么

13. 如果自己写的 Python 程序出错了,怎么办?

发布于: 2021 年 02 月 17 日
13. 如果自己写的 Python 程序出错了,怎么办?

今天是持续写作的第 <font color="red">13</font> / 100 天。

如果你有想要交流的想法、技术,欢迎在评论区留言。


本篇文章主要内容为程序错误与异常处理,顺带会说一下内置模块 logging 。


<center><font color=red>缓解一下视疲劳</font></center>


<center><font color=red>缓解一下视疲劳</font></center>


已完成的文章


  • 1.这才是 Python 学习的正确起手姿势,滚雪球学 Python

  • 2. 无门槛学会数据类型与输入、输出函数,滚雪球学 Python

  • 3. 无转折不编程,滚雪球学 Python

  • 4. 列表一学完,Python 会一半,滚雪球学 Python

  • 5. Python 循环的本质就是一段代码懒得重复写

  • 6. Python 元组,不可变的列表,滚雪球学 Python

  • 7. ✎ 会查新华字典不?会。Python 字典已经掌握了

  • 8. ㊙ Python 集合三板斧,滚雪球学 Python

  • 9. Python 学习过程的第一个山坡,99%的人都倒在了山坡下

  • 10. 比找女朋友还难的技术点,Python 面向对象

  • 11. 用别人写好的代码,完成我的工作,剩下的时间去摸鱼

  • 12. 数据放在本地,心里才更踏实,滚雪球学 Python


**本系列文章将在 2021 年春节前完成,欢迎关注,点赞,评论 --- 梦想橡皮擦**


**想学 Python 爬虫,可以订阅橡皮擦专栏哦~** 🈲🈲🈲 点击发现惊喜 🈲🈲🈲


十三、Python 程序异常处理与 logging 模块


13.1 程序异常


程序异常,就是程序出错了,程序员一般叫做 BUG(八哥),写程序不出错是不可能发生的事情,而程序员要做的事情就是及时的捕获错误,修改错误。


13.1.1 最常见的错误 - 除数为 0


在数学中也存在类似的问题,除数不可以为 0。相同的概念在编程中也是存在的。


num1 = 20num2 = 0num3 = num1 / num2print(num3)
复制代码


运行代码出现下面的错误:


Traceback (most recent call last):  File "D:/gun/2/demo7.py", line 3, in <module>    num3 = num1 / num2ZeroDivisionError: division by zero
复制代码


错误内容就是末尾的 ZeroDivisionError: division by zero ,当出现错误程序崩溃,终止运行。错误异常中也提示了错误出现的行数 line 3 在第三行,但查看行号排查错误在很多时候无法直接解决问题,因为出错的地方不在行号那一行,修改 BUG 的效率一般会随着你对 Python 学习的深入逐步增强改善。


13.1.2 try ... except 语句


刚才的程序出现错误就终止运行了,如何避免程序被强迫终止,出现问题提示出问题,然后继续运行呢?这就是 try ... except 语句使用的场景了。


语法格式:


try:	可能会出错的代码except 异常对象:	处理异常代码
复制代码


按照上述语法格式修改上文代码。


num1 = 20num2 = 0try:    num3 = num1 / num2except ZeroDivisionError:    print("除数不可以为 0 ")
复制代码


此时程序不会报错,当发现除数为 0 会进入异常处理,直接输出除数不能为 0。


try 表示测试代码部分是否存在异常,except 表示捕获异常,前提是出现异常。如果 try 语句中没有任何错误,except 中的代码不会执行。


还有一点需要注意,在 except 后面是异常对象,该异常对象我们设置为 ZeroDivisionError 这是因为已经知道是会出现这个异常,如果在编码过程中不知道会出现哪种异常,依旧会出现错误。


num1 = 20num2 = "abc"try:    num3 = num1 / num2except ZeroDivisionError:    print("除数不可以为 0 ")
复制代码


上述代码依旧会报错,报错的异常为:


Traceback (most recent call last):  File "D:/gun/2/demo7.py", line 4, in <module>    num3 = num1 / num2TypeError: unsupported operand type(s) for /: 'int' and 'str'
复制代码


如果想在 except 后面支持本异常,需要添加上 TypeError


num1 = 20num2 = "abc"try:    num3 = num1 / num2except (ZeroDivisionError,TypeError):    print("除数不可以为 0 ")
复制代码


也可以分开编写:


num1 = 20num2 = "abc"try:    num3 = num1 / num2except ZeroDivisionError:    print("除数不可以为 0 ")
except TypeError: print("除数类型不对")
复制代码


该种写法在书写的时候需要预先知道会提示哪种异常,如果异常不清楚那可以省略异常对象,直接使用下述代码即可。


num1 = 20num2 = "abc"try:    num3 = num1 / num2except:    print("除数不可以为 0 ")
复制代码


13.1.3 try ... except ... else 语句


在 try ... except 语句后面可以增加一个 else 语句,该语句表示的含义可以按照如下描述进行理解,当出现异常的时候执行 except 语句中的代码,当无异常执行 else 语句代码。


num1 = 20num2 = 1try:    num3 = num1 / num2except ZeroDivisionError:    print("除数不可以为 0 ")
except TypeError: print("除数类型不对")
else: print("无异常,会被执行")
复制代码


以上代码无错误,那 else 语句就会被执行到。


13.2 异常类型


13.2.1 常见的异常类型


在编写代码的过程中,你需要掌握一些常见的异常类型,熟记它们可以帮助你快速进行错误排查。


  • AttributeError 某个对象没有属性

  • Exception 通用型异常对象

  • FileNotFoundError 找不到文件

  • IOError 输入输出异常

  • IndexError 索引异常

  • KeyError 键异常

  • NameError 对象名称异常

  • SyntaxError 语法错误

  • TypeError 类型错误

  • ValueError 值错误


以上错误都属于常见错误,其中重点以 Exception 通用异常对象与 SyntaxError 语法错误为主,它们两个是最常出现的。


很多时候其实直接使用通用异常对象 Exception 就可以了,不需要记住所有的异常类型的。


13.2.2 捕捉多个异常


在上文已经接触过捕捉多个异常的语法格式了,可以在学习一下。


try:	可能出错的代码块except 异常对象1:	异常处理代码块except 异常对象2:	异常处理代码块
复制代码


13.2.3 一个 except 捕获多个异常


Python 也支持使用一个 except 捕获多个异常,具体语法格式如下:


try:	可能出错的代码块except (异常对象1,异常对象2...):	异常处理代码块
复制代码


13.2.4 直接抛出异常


捕获到异常之后,可以直接抛出 Python 给内置好的异常信息,例如:


num1 = 20num2 = 0try:    num3 = num1 / num2except ZeroDivisionError as e:    print(e)
except TypeError as e: print(e)
else: print("无异常,会被执行")
复制代码


注意 except 后面异常对象使用 as 关键字起了一个别名叫做 e,然后直接输出 e 就是 Python 内置好的错误信息了。这里的 e 可以为任意名称,遵循变量命名规则即可。


13.3 finally 语句


try ... except 语句还可以和 finally 语句配合,形成下述语法格式:


try:	可能出错的代码块except:	代码出错执行的代码块else:	代码正常执行的代码块finally:	无论代码是否有异常出现都会执行的的代码块
复制代码


finally 语法需要与 try 语句配合使用,无论是否有异常出现都会执行该语句内容,具体代码大家可以自行测试即可。


13.4 日志模块 logging


13.4.1 logging 模块


在 Python 中为了更好的记录程序错误信息,提供了一个 logging 模块供我们使用,该模块提供了 5 个等级用于标记日志信息的等级。


  1. DEBUG 等级,使用 logging.debug() 显示

  2. INFO 等级,记录类的日志

  3. WARNING 等级,警告级别,存在潜在风险

  4. ERROR 等级,引发错误

  5. CRITICAL 等级,引发系统出现问题,最高等级


导入 logging 模块之后,可以使用下述内容设置显示信息的等级。


import logginglogging.basicConfig(level=logging.DEBUG)
复制代码


五个等级输出函数如下:


import logginglogging.basicConfig(level=logging.DEBUG)
logging.debug("DEBUG")logging.info("INFO")logging.warning("WARNING")logging.error("ERROR")logging.critical("CRITICAL")
复制代码


输出内容如下:


DEBUG:root:DEBUGINFO:root:INFOWARNING:root:WARNINGERROR:root:ERRORCRITICAL:root:CRITICAL
复制代码


上述代码因为设置的等级是 DEBUG,所以所有的日志信息都会输出,如果设置为 WARNING,例如下述代码,查看输出内容。


import logging# 注意看这里的设置logging.basicConfig(level=logging.WARNING)
logging.debug("DEBUG")logging.info("INFO")logging.warning("WARNING")logging.error("ERROR")logging.critical("CRITICAL")
复制代码


因为设置了 logging 输出等级是 WARNING,所以较低等级的 DEBUG 与 INFO 将不再输出,这样可以随着程序开发不断的提高等级,最终提高到 CRITICAL。


13.4.2 格式化 logging 日志信息


可以在全局进行 logging 信息的格式化,语法格式如下:


logging.basicConfig(level=logging.WARNING,format = "")
复制代码


在不设置 format 的时候,默认输出的日志信息如下,所以输出内容前面都存在一个 DEBUG:root: 内容,如果设置 format="" 即可删除原内容。


DEBUG:root:DEBUGINFO:root:INFOWARNING:root:WARNINGERROR:root:ERRORCRITICAL:root:CRITICAL
复制代码


设置 format = "" ,代码如下:


import logginglogging.basicConfig(level=logging.WARNING,format= "")
复制代码


其余内容不需要修改,输出的日志信息,已经没有前面的默认关键词了。


WARNINGERRORCRITICAL
复制代码


对于日志信息的格式化,还可以增加 asctime ,该内容为时间信息,例如下述代码:


import logginglogging.basicConfig(level=logging.WARNING,format= "%(asctime)s")
logging.debug("DEBUG")logging.info("INFO")logging.warning("WARNING")logging.error("ERROR")logging.critical("CRITICAL")
复制代码


使用该内容运行结果发现,要输出的信息没有了,这是因为你在 format 参数中只传了 asctime 一个内容,如果还需要 logging 输出信息,需要增加 message,语法如下:


import logginglogging.basicConfig(level=logging.WARNING,format= "%(asctime)s %(message)s")
logging.warning("WARNING")logging.error("ERROR")logging.critical("CRITICAL")
复制代码


学习过 asctimemessage 之后,你应该对 format 格式化的语法有了一些基本的认知,它应该是一个 %(参数名)s 这样的结构,如果增加一个 logging 等级参数 levelname,尝试一下你可以将其拼接到 format 中吗?


13.4.3 程序日志 logging 输出到文件中


程序日志如果都输出在 Python 控制台,导致的结果就是控制台出现大量的调试信息,很多时候可以将日志信息输出到文件中,而且实现非常简单,只需要增加一个参数 filename 即可解决问题。


import logginglogging.basicConfig(filename = "out.txt",level=logging.WARNING,format= "%(asctime)s %(message)s")
复制代码


执行上述代码之后,会自动在当前根目录(文件与目录可以自己设置)生成一个日志文件。


13.4.4 停用程序日志


使用下述方法停用日志。


logging.disable(level)
复制代码


如果希望全部停用,只需要直接限制等级到 CRITICAL 即可。


import logginglogging.basicConfig(level=logging.WARNING,format= "%(asctime)s %(message)s")logging.disable(level=logging.CRITICAL)logging.debug("DEBUG")logging.info("INFO")logging.warning("WARNING")logging.error("ERROR")logging.critical("CRITICAL")
复制代码


13.5 这篇博客的总结


本篇博客主要写的是异常相关知识,在 Python 代码的编写过程中经常会出现异常,一般情况下程序员都叫做 出 BUG 了,这个 BUG 就是臭虫的意思,表示程序出臭虫了。当然很多时候我们也戏称“无 BUG,不编程”。


发现 BUG,解决 BUG,程序员不是在写 BUG 的路上,就是在改 BUG 的路上,好友哲理。


关于异常部分,还有如下内容可以扩展。


  • 使用 raise 抛出异常

  • 使用 traceback 模块记录异常信息到文件中

  • 程序断言 assert


**想学 Python 爬虫,可以订阅橡皮擦专栏哦~** 🈲🈲🈲🈲 点击发现惊喜 🈲🈲🈲🈲




如果你想跟博主建立亲密关系,可以关注同名公众号 <font color="red">梦想橡皮擦</font>,近距离接触一个逗趣的互联网高级网虫。

博主 ID:梦想橡皮擦,希望大家<font color="red">点赞</font>、<font color="red">评论</font>、<font color="red">收藏</font>。


发布于: 2021 年 02 月 17 日阅读数: 10
用户头像

爬虫 100 例作者,蓝桥签约作者,博客专家 2021.02.06 加入

6 年产品经理+教学经验,3 年互联网项目管理经验; 互联网资深爱好者; 沉迷各种技术无法自拔,导致年龄被困在 25 岁; CSDN 爬虫 100 例作者。 个人公众号“梦想橡皮擦”。

评论

发布
暂无评论
13. 如果自己写的 Python 程序出错了,怎么办?