Python代码中的异常处理 异常基础知识点介绍

鳄鱼君

发表文章数:615

Vieu四代商业主题

高扩展、安全、稳定、响应式布局多功能模板。

¥69 现在购买
首页 » Python » Python代码中的异常处理 异常基础知识点介绍

在Python中,异常会根据错误自动地被触发,也能由代码触发和截获。异常由四个语句处理:
try/except:捕捉由Python或你引起的异常并恢复
try/finally:无论异常是否发生,执行清理行为
raise:手动在代码中触发异常
assert:有条件地在程序代码中触发异常
with/as:实现环境管理器

异常是一种结构化的“超级goto”。异常处理器(try语句)会留下标识,并且可以执行一些代码。在Python中异常可以用于各种用途。这里列举一些常见的用途:

1.错误处理

每当在运行时检测到程序错误时,Python就会引发异常。可以在程序代码中捕捉和响应错误,或者忽略已发生的异常。如果忽略错误,Python默认的异常处理行为将启动:停止程序,打印出错消息。如果不想启动这种默认行为,就要写try语句来捕捉异常并从异常中恢复:当检测到错误时,Python会跳到try处理器,而程序在try之后会重新继续执行

2.事件通知

异常也可用于发出有效状态的信号,而不需在程序间传递结果标志位,或者刻意对其进行测试。例如,搜索的程序可能在失败时引发异常,而不是返回一个整数结果代码(而且这段代码很有可能不会有一个有效的结果)。

3.特殊情况处理

有时,发生了某种很罕见的情况,很难调整代码去处理。通常会在异常处理器中处理这些罕见的情况,从而省去编写应对特殊情况的代码。

4.终止行为

正如将要看到的一样,try/finally语句可确保一定会进行需要的结束运算,无论程序中是否有异常。

5.非常规控制流程

因为异常是一种高级的“goto”,它可以作为实现非常规的控制流程的基础。例如,虽然反向跟踪(backtracking)并不是语言本身的一部分,但它能够通过Python的异常来实现,此外需要一些辅助逻辑来退回赋值语句。Python中没有“go to”语句(谢天谢地!),但是,异常有时候可以充当类似的角色。

默认异常处理器

这个应该不难理解,就是我们所谓的报错,在我们的代码中,会时不时的出现。这就是Python默认的异常处理器。现在编写一个普通的函数,并调用它:

# 定义函数
def fun(obj,index):
    return obj[index]

# 调用函数
obj='eyujun'
print(fun(obj,2))

这是一个普通的函数,通过传入的索引index对对象obj进行索引运算。以上是正常运算,现在我们进行错误运算:对obj末尾以后的位置做索引运算,当函数执行obj[index]就会触发异常:

# 调用函数
obj='eyujun'
print(fun(obj,10))
# .....
# IndexError: string index out of range

Python会替序列检测到超出边界的索引运算,并通过抛出内置的IndexError异常进行报告。因为我们没有捕捉这个异常,所以它将会一直向上返回到程序的顶层,并且启用默认的异常处理器:就是打印标准出错消息。这些消息包括引发的异常还有堆栈跟踪:也就异常发生时,激活的程序行和函数清单!

捕获异常

在很多情况下,我们并不想看到报错。例如,服务器程序一般需要在内部错误发生时依然保持工作,这时候就需要捕获异常:

try:
    obj='eyujun'
    print(fun(obj,10))
except IndexError:
    print('got exeception')

# got exeception

当try代码块执行时触发异常,Python会自动跳至处理器(指出引发的异常名称的except分句下面的代码块)。在实际工作中,try语句不仅会捕捉异常,也会从中回复执行:

def catcher():
    try:
        obj='eyujun'
        print(fun(obj,10))
    except IndexError:
        print('got exeception')
    print('continuing....')
catcher()

在异常捕捉和处理后,程序在捕捉了整个try语句后继续执行:这就是我们之所以得到“continuing….”消息的原因。我们没有看见标准出错消息,而程序也将正常运行下去。

引发异常

想要手动触发异常,直接执行rasie语句。用户触发的异常的捕捉方式和Python引发的异常一样:

try:
    raise IndexError
except IndexError:
    print('got exeception')

# got exeception

如果没捕捉到异常,用户定义的异常就会向上传递,直到顶层默认的异常处理器,并通过标准出错消息终止该程序。

raise IndexError
# ....
# IndexError

assert语句也可以用来触发异常——它是一个有条件的raise,主要是在开发过程中用于调试:

assert False,'Nobody expects the Spanish Inquisition!'

# ...
# AssertionError: Nobody expects the Spanish Inquisition!

用户定义的异常

raise语句触发Python的内置作用域中定义的一个内置异常。我们也可以定义自己的新的异常,它特定于你的程序。用户定义的异常能够通过类编写,它继承自一个内置的异常类:通常这个类的名称叫做Exception。基于类的异常允许脚本建立异常类型、继承行为以及附加状态信息。

class Bad(Exception):    # 用户定义的异常
    pass
def doomed():
    raise Bad()          # 触发异常
try:
    doomed()
except Bad:              # 捕捉异常
    print('got Bad')

# got Bad

终止行为

try语句可以说“finally”,也就是说,它可以包含finally代码块。这看上去就像是异常的except处理器,但是try/finally的组合,可以定义一定会在最后执行时的收尾行为,无论try代码块中是否发生了异常:

def fun(obj,index):
    return obj[index]
try:
    obj = 'eyujun'
    print(fun(obj,3))
finally:             # 终止行为
    print('after fun')
# j
# after fun

如果try代码块完成后没有异常,finally代码块就会执行,而程序会在整个try后继续下去。我们似乎也可以直接在函数调用后输入print,从而完全跳过try:

def fun(obj,index):
    return obj[index]

obj = 'eyujun'
print(fun(obj,3))
print('after fun')

这样编写会存在一个问题:如果函数调用引发了异常,就永远到不了after fun。try/finally组合可避免这种缺点:一旦异常确实在try代码块中发生时,当程序被层层剥开,将会执行finally代码块。

def fun(obj,index):
    return obj[index]
def after():
    try:
        obj = 'eyujun'
        fun(obj,20)
    finally:
        print('after fun')
    print('after try?')
after()

# ...
# IndexError: string index out of range
# after fun

我们没有看到“after try?”消息,因为当异常发生时,控制权在try/finally代码块后中断了。与其相对比的是,Python跳回去执行finally的行为,然后把异常向上传播到前一个处理器(在这个例子中,就是顶层的默认处理器)。如果我们修改这个函数中的调用,使其不触发异常,则finally程序代码依然会执行,但程序就会在try后继续运行。

def fun(obj,index):
    return obj[index]
def after():
    try:
        obj = 'eyujun'
        fun(obj,3)
    finally:
        print('after fun')
    print('after try?')
after()

# after fun
# after try?

在实际应用中,try/except的组合可用于捕捉异常并从中恢复,而try/finally的组合则很方便,可以确保无论try代码块内的代码是否发生了任何异常,终止行为一定会运行。例如,可能使用try/except来捕捉从第三方库导入的代码所引发的错误,然后以try/finally来确保关闭文件,或者终止服务器连接的调用等行为一定会执行。

异常编码细节

从Python 2.5起,finally子句可以同样出现在try语句以及except和else语句中(之前,它们不能组合)。此外,从Python 3.0和Python 2.6开始,新的with环境管理器语句成为正式的,并且用户定义的异常现在必须编写为类实例。此外,Python 3.0支持raise语句和except子句的略微修改的语法。

try/except/else语句

在Python 2.5中,except和finally可以混在一个try语句中。try是复合语句,它的最完整的形式如下所示。首先是以try作为首行,后面紧跟着(通常)缩进的语句代码,然后是一个或多个except分句来识别要捕捉的异常,最后是一个可选的else分句。try、except以及else这些关键字会缩进在相同的层次(也就是垂直对齐)。为了方便参考,以下是其在Python 3.0中的一般格式。

try:
# 首先运行
except :
# 如果在try块期间引发name1,则运行
except (name2,name3):
# 如果出现这些异常,则运行
except as :
# 如果name4被引发,则运行,并获取引发的实例
except:
# 引发的所有异常运行
else:
# 如果在try块期间未引发异常,则运行

在这个语句中,try首行底下的代码块代表此语句的主要动作:试着执行的程序代码。Except子句定义try代码块内引发的异常的处理器,而else子句(如果编写了的话)则是提供没发生异常时要执行的处理器。在这里的元素和raise语句功能有关。

以下是try语句的运行方式。当try语句启动时,Python会标识当前的程序环境,这样一来,如果有异常发生时,才能返回这里。try首行下的语句会先执行。接下来会发生什么事情,取决于try代码块语句执行时是否引发异常。

•如果try代码块语句执行时的确发生了异常,Python就跳回try,执行第一个符合引发异常的except子句下面的语句。当except代码块执行后(除非except代码块引发了另一异常),控制权就会到整个try语句后继续执行。
•如果异常发生在try代码块内,没有符合的except子句,异常就会向上传递到程序中的之前进入的try中,或者如果它是第一条这样的语句,就传递到这个进程的顶层(这会使Python终止这个程序并打印默认的出错消息)。
•如果try首行底下执行的语句没有发生异常,Python就会执行else行下的语句(如果有的话),控制权会在整个try语句下继续。

换句话说,except分句会捕捉try代码块执行时所发生的任何异常,而else子句只在try代码块执行时不发生异常才会执行。

except子句是专注于异常处理器的:捕捉只在相关try代码块中的语句所发生的异常。尽管这样,因为try代码块语句可以调用写在程序其他地方的函数,异常的来源可能在try语句自身之外。

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《Python代码中的异常处理 异常基础知识点介绍》 发布于2020-06-18

分享到:
赞(0) 赏杯咖啡

评论 抢沙发

8 + 8 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册