一文读懂Python中的异常处理-程序员宅基地

技术标签: python  异常  

异常处理在任何一门编程语言里都是值得关注的一个话题,良好的异常处理可以让你的程序更加健壮,清晰的错误信息更能帮助你快速修复问题。在Python中,和不部分高级语言一样,使用了try/except/finally语句块来处理异常,如果你有其他编程语言的经验,实践起来并不难。

异常处理语句 try...excpet...finally

实例代码

defdiv(a, b):

try:

print(a / b)

exceptZeroDivisionError:

print("Error: b should not be 0 !!")

exceptExceptionase:

print("Unexpected Error: {}".format(e))

else:

print('Run into else only when everything goes well')

finally:

print('Always run into finally block.')

# tests

div(2,0)

div(2,'bad type')

div(1,2)

# Mutiple exception in one line

try:

print(a / b)

except(ZeroDivisionError, TypeError)ase:

print(e)

# Except block is optional when there is finally

try:

open(database)

finally:

close(database)

# catch all errors and log it

try:

do_work()

except:

# get detail from logging module

logging.exception('Exception caught!')

# get detail from sys.exc_info() method

error_type, error_value, trace_back = sys.exc_info()

print(error_value)

raise

总结如下

except语句不是必须的,finally语句也不是必须的,但是二者必须要有一个,否则就没有try的意义了。

except语句可以有多个,Python会按except语句的顺序依次匹配你指定的异常,如果异常已经处理就不会再进入后面的except语句。

except语句可以以元组形式同时指定多个异常,参见实例代码。

except语句后面如果不指定异常类型,则默认捕获所有异常,你可以通过logging或者sys模块获取当前异常。

如果要捕获异常后要重复抛出,请使用raise,后面不要带任何参数或信息。

不建议捕获并抛出同一个异常,请考虑重构你的代码。

不建议在不清楚逻辑的情况下捕获所有异常,有可能你隐藏了很严重的问题。

尽量使用内置的异常处理语句来 替换try/except语句,比如with语句,getattr()方法。

抛出异常 raise

如果你需要自主抛出异常一个异常,可以使用raise关键字,等同于C#和Java中的throw语句,其语法规则如下。

raiseNameError("bad name!")

raise关键字后面需要指定你抛出的异常类型,一般来说抛出的异常越详细越好,Python在exceptions模块内建了很多的异常类型,通过使用dir()函数来查看exceptions中的异常类型,如下:

importexceptions

# ['ArithmeticError', 'AssertionError'.....]

printdir(exceptions)

当然你也可以查阅Python的文档库进行更详细的了解。

https://docs.python.org/2.7/library/exceptions.html#bltin-exceptions

自定义异常类型

Python中也可以自定义自己的特殊类型的异常,只需要要从Exception类继承(直接或间接)即可:

classSomeCustomException(Exception):

pass

一般你在自定义异常类型时,需要考虑的问题应该是这个异常所应用的场景。如果内置异常已经包括了你需要的异常,建议考虑使用内置 的异常类型。比如你希望在函数参数错误时抛出一个异常,你可能并不需要定义一个InvalidArgumentError,使用内置的ValueError即可。

经验案例

传递异常 re-raise Exception

捕捉到了异常,但是又想重新引发它(传递异常),使用不带参数的raise语句即可:

deff1():

print(1/0)

deff2():

try:

f1()

exceptExceptionase:

raise# don't raise e !!!

f2()

在Python2中,为了保持异常的完整信息,那么你捕获后再次抛出时千万不能在raise后面加上异常对象,否则你的trace信息就会从此处截断。以上是最简单的重新抛出异常的做法。

还有一些技巧可以考虑,比如抛出异常前对异常的信息进行更新。

deff2():

try:

f1()

exceptExceptionase:

e.args += ('more info',)

raise

如果你有兴趣了解更多,建议阅读这篇博客。

http://www.ianbicking.org/blog/2007/09/re-raising-exceptions.html

Python3对重复传递异常有所改进,你可以自己尝试一下,不过建议还是同上。

Exception 和 BaseException

当我们要捕获一个通用异常时,应该用Exception还是BaseException?我建议你还是看一下 官方文档说明,这两个异常到底有啥区别呢? 请看它们之间的继承关系。

BaseException

+-- SystemExit

+-- KeyboardInterrupt

+-- GeneratorExit

+-- Exception

     +-- StopIteration...

     +-- StandardError...

     +-- Warning...

从Exception的层级结构来看,BaseException是最基础的异常类,Exception继承了它。BaseException除了包含所有的Exception外还包含了SystemExit,KeyboardInterrupt和GeneratorExit三个异常。

有此看来你的程序在捕获所有异常时更应该使用Exception而不是BaseException,因为另外三个异常属于更高级别的异常,合理的做法应该是交给Python的解释器处理。

except Exception as e和 except Exception, e

代码示例如下:

try:

do_something()

exceptNameErrorase:# should

pass

exceptKeyError, e:# should not

pass

在Python2的时代,你可以使用以上两种写法中的任意一种。在Python3中你只能使用第一种写法,第二种写法被废弃掉了。第一个种写法可读性更好,而且为了程序的兼容性和后期移植的成本,请你也抛弃第二种写法。

raise "Exception string"

把字符串当成异常抛出看上去是一个非常简洁的办法,但其实是一个非常不好的习惯。

ifis_work_done():

pass

else:

raise"Work is not done!"# not cool

上面的语句如果抛出异常,那么会是这样的:

Traceback (most recent call last):

File"/demo/exception_hanlding.py", line48,in

raise"Work is not done!"

TypeError: exceptions must be old-style classesorderivedfromBaseException,notstr

这在Python2.4以前是可以接受的做法,但是没有指定异常类型有可能会让下游没办法正确捕获并处理这个异常,从而导致你的程序挂掉。简单说,这种写法是是封建时代的陋习,应该扔了。

使用内置的语法范式代替try/except

Python 本身提供了很多的语法范式简化了异常的处理,比如for语句就处理的StopIteration异常,让你很流畅地写出一个循环。

with语句在打开文件后会自动调用finally中的关闭文件操作。我们在写Python代码时应该尽量避免在遇到这种情况时还使用try/except/finally的思维来处理。

# should not

try:

f = open(a_file)

do_something(f)

finally:

f.close()

# should

withopen(a_file)asf:

do_something(f)

再比如,当我们需要访问一个不确定的属性时,有可能你会写出这样的代码:

try:

test = Test()

name = test.name# not sure if we can get its name

exceptAttributeError:

name ='default'

其实你可以使用更简单的getattr()来达到你的目的。

name = getattr(test,'name','default')

最佳实践

最佳实践不限于编程语言,只是一些规则和填坑后的收获。

只处理你知道的异常,避免捕获所有 异常然后吞掉它们。

抛出的异常应该说明原因,有时候你知道异常类型也猜不出所以然的。

避免在catch语句块中干一些没意义的事情。

不要使用异常来控制流程,那样你的程序会无比难懂和难维护。

如果有需要,切记使用finally来释放资源。

如果有需要,请不要忘记在处理异常后做清理工作或者回滚操作。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40907382/article/details/79851056

智能推荐

linux 压缩和解压缩zip、unzip_unzip解压后删除-程序员宅基地

文章浏览阅读728次。zip基本用法zip [参数] [打包后的文件名] [打包的目录路径]常用参数:-a 将文件转成ASCII模式-F 尝试修复损坏的压缩文件-h 显示帮助界面-m 将文件压缩之后,删除源文件-n 特定字符串 不压缩具有特定字尾字符串的文件-o 将压缩文件内的所有文件的最新变动时间设为压缩时候的时间-q 安静模式,在压缩的时候不显示指令的执行过程-r 将指定的目录下的所有子目录以及文件一起处理-S 包含系统文件和隐含文件(S是大写)unzip基本用法_unzip解压后删除

降低AI辅写率小技巧:让内容更具原创性和独特性的七大秘诀-程序员宅基地

文章浏览阅读629次,点赞9次,收藏12次。通过掌握和运用这些秘诀,我们可以让内容更具原创性和独特性,从而更好地展示我们的思想和观点。通过阅读、学习和实践,提高自己的写作技巧和表达能力,以更好地掌握降低AI辅写率的方法。此外,关注行业动态和最新技术进展,了解最新的降低AI辅写率技巧和策略,以保持自己在写作领域的领先地位。针对发现的问题,及时进行修改和调整,确保内容的原创性和独特性。在写作过程中,尝试融入自己的见解、观点和独特风格,使内容更具个性化和创新性。明确的目的和主题将确保你的内容始终围绕核心思想展开,减少不必要的偏离和重复。

C++如何选择类型_c++ 数据类型的选择原则-程序员宅基地

文章浏览阅读379次。和C语言一样,C++的设计准则之一也是尽可能地接近硬件。C++的算术类型必须满足各种硬件特质,所以它们常常显得繁杂而令人不知所措。事实上,大多数程序员能够(也应该)对数据类型的使用做出限定从而简化选择的过程。以下是选择类型的一些经验准则:●当明确知晓数值不可能为负时,选用无符号类型。●使用int执行整数运算。在实际应用中,short常常显得太小而long-般和int有一样的尺寸。如果你的数值超过了int的表示范围,选用long long。●在算术表达式中不要使用 char或bool,只有在._c++ 数据类型的选择原则

错误: 无效的源发行版:18 :亲测有效_java: 错误: 无效的源发行版:18-程序员宅基地

文章浏览阅读6.6k次,点赞3次,收藏18次。错误: 无效的源发行版:18 :亲测有效_java: 错误: 无效的源发行版:18

软考中项:常考知识点及案例分析要点总结_软考中项案例分析-程序员宅基地

文章浏览阅读5.6k次,点赞7次,收藏60次。前言系统集成项目管理工程师考试(简称软考中项),其中案例分析也是很大一部分考试内容,目前正在学习中,现总结一些可能会考到的知识点供大家参考。1、项目干系人:每个项目的关键干系人除客户和用户外,还包括如下一些人。项目经理:负责管理项目的人。执行组织:指其员工最直接参品顶日工作的单位。项目团队成员:执行项目工作的群体。项目发起人:职能经理:影响者项目管理办公室(Project Management Office, PMO)2、项目建议书项目建议书(又称立项申请)是项目建设单位向上级主_软考中项案例分析

WebRTC--三大线程-程序员宅基地

文章浏览阅读11次。【代码】WebRTC--三大线程。

随便推点

[802.11]IEEE 802.11的帧格式介绍_ieee80211数据帧格式 408-程序员宅基地

文章浏览阅读4.9w次,点赞33次,收藏211次。一、IEEE 802.11的帧格式1.1 IEEE 802.11是什么? 802.11是国际电工电子工程学会(IEEE)为无线局域网络制定的标准。目前在802.11的基础上开发出了802.11a、802.11b、802.11g、802.11n、802.11ac。并且为了保证802.11更加安全的工作,开发出了802.1x、802.11i等协议1.2 IEEE 802.1..._ieee80211数据帧格式 408

纯前端实现—JQ轮播图(轮播图完全版)_jq轮播图全集网址-程序员宅基地

文章浏览阅读4w次,点赞16次,收藏47次。实现效果:前面有篇文讲解过鼠标轮播图——https://gu-han-zhe.blog.csdn.net/article/details/121315021,还得鼠标点,有点麻烦,所以这篇给B格提升些!实现JQ轮播图(完全版~)! JQ轮播图 源码:<!DOCTYPE html><html lang="en"><head> <_jq轮播图全集网址

liunx环境安装elasticsearch-7.XX_avxf-程序员宅基地

文章浏览阅读353次。解压压缩包:tar -avxf elasticsearch-7.10.2-linux-aarch64.tar.gz修改config/elasticsearch.yml:vi config/elasticsearch.yml取消下列项注释并修改:cluster.name: my-application #集群名称node.name: node-1 #节点名称#数据和日志的存储目录path.data: /home/elasticsearch/datapath.logs: /home/ela_avxf

HTML中的& nbsp; & ensp; & emsp;等6种空格标记 (实用)_html &nbsp;-程序员宅基地

文章浏览阅读2k次。原文出处:https://www.cnblogs.com/Salicejy/p/css.html代码: 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>HTML中的& nbsp..._html

开发者们看过来,这场长沙的开发者技术大会正在为你而来~-程序员宅基地

文章浏览阅读235次。开发者们看过来,这场长沙的开发者技术大会正在为你而来~ 看过去,历史的尘埃与沧海桑田古语有云“近代中国,湖南独撑半边天”,湖南长沙,作为湖南省的省会,自古以来便是各界风云人士兴起之地。随着互联网时代的到来,长沙,这座历史悠久的文化名城,不仅仅是中国互联网人才的基地,更是成为已经逐渐成为中南地区具有足够影响力的实力当担,包括芒果视频、映客直播等..._长沙开发者大会

微信APP支付V3(java版本)-程序员宅基地

文章浏览阅读483次,点赞7次,收藏10次。开箱即用,有任何问题可私信