第11课 异常处理

一、异常处理的意义

1. 异常机制已经成为衡量一门编程语言是否成熟的标准之一,使用异常处理机制的Python程序会有更好的容错性。

2. 没有人能够保证自己写的程序永远不会出错,既是程序没有错误,也不能保证用户按你的意图来输入,另外还有系统的稳定性,计算硬件是否损坏,网络掉线等诸多情况。

二、异常处理机制

1. 使用try...except捕获异常

1)例如,通常在程序运行时,用户可以随意输入,程序不会因为用户的输入不合法而突然间退出,而是向用户提示输入不合法,并请用户再次输入。

那么我们就希望有一种强大的if块来解决这个非法输入的问题:

if 用户输入不合法:

    alert 输入不合法

    go retry

else:

    #业务实现代码

2)但是“用户输入不合法”这个条件怎么定义呢?我们可以使用正则表达式与用户的输入进行匹配。但现实中不合法的情况非常多,想让程序一次处理所有的错误,我们可以将上面的伪代码修改为:

if 一切正常:

    #业务实现代码

就是:

    alert 输入不合法

    goto retry

3) 但“一切正常”依然是很抽象的,无法转化成代码。在这种情形下Python提供了一种假设:如果程序可以顺利运行,那么就是“一切正常”。由此得出Python异常处现机制的语法结构:

try:

    #业务实现代码

except(Error1, Error2, ....) as e:

    alert 输入不合法

    goto retry

4) 这样如果执行try块里的业务实现代码是出现异常,系统会自动生成一个异常对象,该异常对象被提交给Python解释器,这个过程被称为引发异常。

5)当Python解释器收到异常对象时,会寻找处理该异常对象的except块,如果找到合适的except块,则把该过程称为捕捉异常。如果Python解释器找到不捕获异常的except块,则运行时环境终止,Python解释器也将退出。

6)不管代码块是否处于try中,或except块中,只要执行该代码时了现了异常,系统总会自动生成一个Error对象。

7) try 可以有多个except块,这是为了针对不同的异常类提供不同的异常处理方式。当系统发生不同意外情况时,系统会生成不同的异常对象。如果try被执行一次,,则try后面只有一个except被执行,除非放在循环中,使用continue开始下一次循环。

2. 异常类

1)Python的所有异常类的基类是BaseException, 但是如果用户果自定义异常,则一概继承Exception类。

2)BaseException的主要子类是Exception,所在不管是系统的异常类,还是用户自定义异常类,都是从Exception派生。

3)异常捕获实例:

>>> import sys

>>> try:

a = int(sys.argv[1]) # 代表当前运行的程序所提供的第一个参数

b = int(sys.argv[2])# 代表当前运行的程序所提供的第二个参数

c = a/b

print("您输入的两个数相除的结果是:",c)

except IndexError:

print("索引错误:运行程序时输入的参数个数不够")

except ValueError:

print("数值错误:程序只能接受整数参数")

except ArithmeticError:

print("算术错误")

except Exception:

print("未知异常")

3. 多异常捕获:指一个Except块可以捕获多种类型的异常。例如:

>>> import sys

>>> try:

a = int(sys.argv[1])

b = int(sys.argv[2])

c = a/b

print("您输入的两个数相除的结果是:",c)

except (IndexError, ValueError, ArithmeticError):

print("程序发生了数组越界、格式错误、算术异常之一")

except: # 此处的省略也是合法的,一般放在最后

print("未知异常")

程序发生了数组越界、格式错误、算术异常之一

4. 访问异常信息

1)如果程序需要在except块中访问异常对象的相关信息,则可以通过为异常对象声明变量来实现。

2)所在的异常对象都包含如下几个对象和方法:

args: 该属性返回异常的错误编号和描述字符串

errno:该属性返回异常的错误编号

strerror:该属性返回异常的描述字符串

with_traceback():通过该方法可以处理异常的传播轨迹

3)程序访问异常信息实例:

>>> def foo():

try:

fis = open("a.txt")

except Exception as e:

print(e.args)

print(e.errno)

print(e.strerror)

>>> foo()

#运行结果如下:

(2, 'No such file or directory')

2

No such file or directory

5. else块

1) 在Python异常处理流程中还可添加一个else块,当try块没有出现异常时,程序会执行else块。

例如:

>>> s = input("请输入除数:")

请输入除数:5

>>> try:

result = 20/int(s)

print('20除以%s的结果是:%g'%(s,result))

except ValueError:

print('值错误,您必须输入数值')

except ArithmeticError:

print('算术错误,您不能输入0')

else:

print('没有出现异常')

#运行结果如下:

20除以5的结果是:4

没有出现异常

2)实际上大部分语言异常处理都没有else块,可以将else块的内容直接放到try后面。但Python异常处理使用else块也不是多余的语法。因为在else块中的异常不会被except捕获,该异常会传给Python解释器导致程序中止。

3)如果希望某段代码的异常,能被后面的except捕获,那么就应该放在try块中;如果不希望被except捕获,就应该放在else块中。

6. 使用finally回收资源

1)为了能够保证回收try块中打开的一些物理资源(如数据库连接、网络连接和磁盘文件),异常处理机制提供了finally块。

2)Python 完整的异常处理语法结构如下:

try:

    #业务实现代码

except SubException1 as e:

    #异常处理块1

except SubException2 as e:

    #异常处理块2

else:

    #正常处理块

finally:

    #资源回收块


三、使用raise引发异常

1. 如果程序中数据或执行与现实的需求不符,但是系统不会判断这样的异常,只能程序员来决定是否引发异常,此时可以使用raise语句来完成这种自行引发的异常。

2. raise语句三种常见的用法:

1) 单独一个raise,该语句引发当前上下文中捕获的异常,或默认引发RuntimeError异常。

2)raise后带一个异常类,该语句引发指定的异常类。

3)raise后带一个异常对象,该语句引发制定的异常对象。

以上三种最终都是引发一个异常实例,每次只能引发一个异常实例。

3. 用户引发异常的两种方式:raise和except,例如:

>>> def main():

try: # 使用try...except来捕获异常,此时出现异常也不会传给调用它的main()函数

mtd(3)

except Exception as e:

print('程序出现异常类是:',e)

mtd(3) #不使用try...except来捕获异常,异常会传播并导致程序中止

>>> def mtd(a):

if a>0:

raise ValueError("a的值大于0,不符合要求")

>>> main()


四、异常的传播轨迹

1. 异常只要没有被完全捕获,异常就会从发生异常的函数或方法向外传播,首先传给该函数或方法的调用者,然后,,直到传给Python解释器,Python解释器就会中止程序,并打印异常传播的轨迹信息。所以通常我们看到大段的异常信息,并不一定发生很多严重的问题,可能只是一个异常引发的。

2. Python专门提供trackback模块来处理异常传播的轨迹,两种常用的方法是:

1)trackback.print_exc(): 将异常传播轨迹输出到控制台或文件中。

2) format_exc():将异常传播轨迹转换成字符串。

五、异常处理规则

1.  不要过度使用异常处理,注意以下两点:

1) 需要编写错误处理代码,而不是简单的用异常来代替处理。

2)  不能用异常来代替流程控制。

2.  不要使用过度庞大的try块:try块越大,发生异常的可能性就越大。而且在庞大的try块后势必有大量的except块,这时要判断各个块之间的逻辑关系,编写程序会变得更加复杂。

3. 不要忽略捕捉到的异常: 程序应该尽量修改异常,保证程序继续运行;不要将本层的异常传给上一层去处理。

六、本节回顾

1. 你怎么理解异常处理机制?

2. Python异常处理的5个关键字是什么?(try\ except\else\finally\raise)

3. 如何使用raise引发异常?

4. 如何获得异常的源头和轨迹?

5.异常处理的原则有哪些?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容