前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python之异常处理

Python之异常处理

作者头像
AsiaYe
发布2019-11-06 15:29:03
4530
发布2019-11-06 15:29:03
举报
文章被收录于专栏:DBA随笔DBA随笔
Python之异常处理

1

Python中的错误处理

在程序运行的过程中,难免会出现这样那样的错误,有些错误是我们自己程序编写上有问题,也就是程序员听了会砍人的那句话,"哟,写bug呢!",还有一种是无法预测的错误,例如磁盘写满了,又或者从网络抓取数据的时候,网络连接突然崩溃等等。Python中内置了一套异常处理机制,可以帮助我们对这些错误进行处理。他就是try...except...finally的错误处理机制。

首先我们来看一个应用实例:

代码语言:javascript
复制
try:
    print('try...')
    r =  / 
    print('result:', r)
except ZeroDivisionError as e:
    print('except:', e)
finally:
    print('finally...')
print('END')

上面的方法中,当我们认为某些代码可能存在一定的安全隐患的时候,可以使用try来运行这段代码,这样做的好处是,如果这段代码真的存在错误,则后续的代码不会执行,而是会直接跳转至错误处理代码,也就是except模块,执行完except之后,如果有finally语句,则执行finally语句,否则执行完毕,上面的代码很明显,除数为0的算法肯定是错误的。我们把它写成一个函数test(),可以看到输出值如下(代码可以左滑):

代码语言:javascript
复制
>>> def test(a):
...     try:
...             print('try...')
...             r =  / a
...             print('result:', r)
...     except ZeroDivisionError as e:
...             print('except:', e)
...     finally:
...             print('finally...')
...     print('END')
...     return 
... 
>>> a=test()
try...
('result:', )
finally...
END
>>> b=test()
try...
('except:', ZeroDivisionError('integer division or modulo by zero',))
finally...
END
>>> 

我们输入参数0的时候,函数返回了错误码和相应的提示。

在上面的例子中,只定义了一种错误,实际情况中,可能有各种各样的非法输入,这就需要我们制定不同的except,从而对真正的错误原因进行区分:

代码语言:javascript
复制
>>> def test(a):
...     try:
...             print('try...')
...             r =  / int(a)
...             print('result:', r)
...     except ValueError as e:
...             print('ValueError:', e)
...     except ZeroDivisionError as e:
...             print('ZeroDivisionError:', e)
...     finally:
...             print('finally...')
...     print('END')
... 
>>> a=test('a')
try...
('ValueError:', ValueError("invalid literal for int() with base 10: 'a'",))
finally...
END
>>> b=test()
try...
('result:', )
finally...
END
>>> c=test()
try...
('ZeroDivisionError:', ZeroDivisionError('integer division or modulo by zero',))
finally...
END
>>> 

上面的结果可以看出,当我们输入一个字母a的时候,返回的错误结果和输入数字0的结果不同,但是他们都触发了异常捕获。

使用try...except还有另外一个好处,就是可以跨越多层调用,比如函数main()调用bar(),bar()调用foo(),如果foo()函数出错了,此时,只要main函数捕获到了,就可以进行处理:

代码语言:javascript
复制
def foo(s):
    return  / int(s)

def bar(s):
    return foo(s) * 

def main():
    try:
        foo('0')
    except Exception as e:
        print('Error:', e)
    finally:
        print('finally...')

也就是说,不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以了。这样一来,就大大减少了写try...except...finally的麻烦。

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。来看一个错误的例子:

代码语言:javascript
复制
# err.py:
def foo(s):
    return  / int(s)

def bar(s):
    return foo(s) * 

def main():
    bar('0')

main()

当我们调用这个文件的时候,会出现如下的错误:

代码语言:javascript
复制
$ python err.py
Traceback (most recent call last):
  File "err.py", line , in <module>
    main()
  File "err.py", line , in main
    bar('0')
  File "err.py", line , in bar
    return foo(s) * 
  File "err.py", line , in foo
    return  / int(s)
ZeroDivisionError: division by zero

层层分析,最后我们可以发现是在foo函数中使用0作为分母,从而出现了错误。这个过程中,我们可以看到函数的调用栈是由外而内的。

2

记录错误,继续执行

当出现错误的时候,如果我们想要继续执行后面的程序,对当前的错误仅仅做一个捕获操作,我们可以使用Python内置的logging模块:

代码语言:javascript
复制
# err_logging.py

import logging

def foo(s):
    return  / int(s)

def bar(s):
    return foo(s) * 

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('继续执行,结果是...')

当我们对上面这段代码进行执行的时候,我们可以看到如下结果:

代码语言:javascript
复制
ERROR:root:integer division or modulo by zero
Traceback (most recent call last):
  File "<stdin>", line , in main
  File "<stdin>", line , in bar
  File "<stdin>", line , in foo
ZeroDivisionError: integer division or modulo by zero
继续执行,结果是...

函数最终还是执行了print,但是将中途所有的错误都捕获到了。这就是logging的作用,需要注意的是,在使用logging之前,先要对logging模块进行导入。通过配置,logging还可以把错误记录到日志文件中,方便以后排查。

3

抛出错误

在Python中,每一个错误都是一个class,所有的错误类型都继承自BaseException,在使用except的时候需要注意,它不但不获该类型的错误,还把其子类的错误一网打尽。捕获一个错误就是捕获该class的一个实例,Python内置的函数会抛出很多类型的错误,如果我们想自己自定义一个错误,可以使用下面的方法:

代码语言:javascript
复制
# err_raise.py
class FooError(ValueError):
    pass

def foo(s):
    n = int(s)
    if n==:
        raise FooError('invalid value: %s' % s)
    return  / n

foo('0')

执行上面这段代码,我们可以通过跟踪找到我们自己定义的错误类型:

代码语言:javascript
复制
>>> python err_raise.py 
Traceback (most recent call last):
  File "<stdin>", line , in <module>
  File "<stdin>", line , in foo
__main__.FooError: invalid value: 
>>> 

只有在必要的时候才定义我们自己的错误类型。如果可以选择Python已有的内置的错误类型(比如ValueErrorTypeError),尽量使用Python内置的错误类型。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
日志服务
日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集、日志存储到日志检索,图表分析、监控告警、日志投递等多项服务,协助用户通过日志来解决业务运维、服务监控、日志审计等场景问题。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档