python错误处理 一

先看一个例子:

>>> def first_example(n):
...     return 1 / n
...
>>> first_example(5)
0.2
>>> first_example(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in first_example
ZeroDivisionError: division by zero
>>>
从例子中得知,n不能为0,否则将会报一个ZeroDivisionError
(除数不能为0)的错误,我们需要对错误进行处理,比如说当发生
的时候我们可以事先约定一个错误代码,这样当以后出错的时候就可
出错的原因。而上面的ZeroDivisionError就是系统内定的一个
错误代码。

通常在python中我们使用,以下格式来定义一个错误代码:

>>> def first_example(n):
...     try:
...             return 1 / n
...     except ZeroDivisionError as error:
...             print('错误信息:',error)
...
>>> first_example(1)
1.0
>>> first_example(0)
错误信息: division by zero
>>>
将你需要执行的代码块(该代码块运行时可能出错)放
在try语句里面,将出错类型放在except后面,并给其
赋一个引用变量,下面的print是打印错误信息,前半
部分是自定义字符串。

看第二个例子,函数之间的 错误处理:

>>> def too(n):
...     return 1 / n
...
>>> def foo(n):
...     return too(n)
...
>>> def second_example(n):
...     try:
...             print(foo(n))
...     except ZeroDivisionError as a:
...             print('出错原因:',a)
...
>>> second_example(2)
0.5
>>> second_example(0)
出错原因: division by zero
>>>

我们继续往下看,我们在上面的例子上进行修改:

>>> def too(n):
...     return 1 / n
...
>>> def foo(n):
...     return too(n) * 3
...
>>> def second_example(n):
...     try:
...             print(foo(n))
...     except ZeroDivisionError as a:
...             print('出错原因:',a)
...     else:
...             print('看看我的出现规则')
...
>>>
>>> second_example(2)
1.5
看看我的出现规则
>>> second_example(0)
出错原因: division by zero
不难看出,else语句块是在没有出错的时候执行
出错的时候就不再执行

我们再进行修改一下 :

>>> def too(n):
...     return 1 / n
...
>>> def foo(n):
...     return too(n) * 3
...
>>> def second_example(n):
...     try:
...             print(foo(n))
...     except ZeroDivisionError as a:
...             print('出错原因:',a)
...     finally:
...             print('我是finally代码块')
...
>>> second_example(2)
1.5
我是finally代码块
>>> second_example(0)
出错原因: division by zero
我是finally代码块

可以看出,不管代码有没有出错,finally代码块都会执行

我们再增加一点东西:

>>> def too(n):
...     return int(n)
...
>>> def foo(s):
...     a = s.split('+')
...     b = map(too,a)
...     return reduce(lambda x, y: x + y , b)
>>> def main(q,w):
...     try :
...             print(1 / q)
...             print(w + '= ',foo(w))
...     except ZeroDivisionError as error:
...             print('错误信息:',error)
...     except ValueError as error:
...             print('错误信息:',error)
...     finally:
...             print('代码执行完毕')
...
>>> main(2,'100 + 23 + 45')
0.5
100 + 23 + 45=  168
代码执行完毕
>>> main(0,'100 + 23 + 45')
错误信息: division by zero
代码执行完毕
>>> main(2,'100 + 23 + 4.5')
0.5
错误信息: invalid literal for int() with base 10: ' 4.5'
代码执行完毕
>>> main(0,'100 + 23 + 4.5')
错误信息: division by zero
代码执行完毕
我们还是将需要执行但可能出错的代码放在try
语句中,但我们有两个except,因为我们会猜测
需要执行的代码可能不止报一个错误。所以我们可
以写多个except

python 错误也是class,所有的错误类型都继承自
BaseException,所以在写except的时候我们应该
注意,如果有多个except,父类错误类型在前面的
except中,子类错误类型在后面的except中,那当
出现子类错误类型 的时候,报的是父类错误类型,
子类错误类型永远不会有执行的机会,举个例子:

>>> def third_example(n):
...     try:
...             return 1 / n
...     except BaseException as a:
...             print('BaseException',a)
...     except ZeroDivisionError as error:
...             print('ZeroDivisionError',error)
...
>>> third_example(0)
BaseException division by zero
所以为了避免这种情况,我们应该把表示范
围小的子类错误类型放前面。

常见的错误类型和继承关系进入这个链接:
常见错误类型和继承关系

错误处理的方式还有一种叫断言(assert):

>>> def odd(n):
...     assert n
...     return 1 / n
...
>>> def fourth_example(n):
...     print(odd(n))
...
>>> fourth_example(2)
0.5
>>> fourth_example(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in fourth_example
  File "<stdin>", line 2, in odd
AssertionError
>>>
断言的语法是,当断言后面的语句为真时,继续往下执行,
当为假时就会报一个AssertionError的错误提示

我们再来看一下assert的升级版本:

>>> def odd(n):
...     if n == 0:
...             raise ValueError('0不能做除数')
...     return 1 / n
...
>>> def fourth_example(n):
...     print(odd(n))
>>> fourth_example(2)
0.5
>>> fourth_example(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in fourth_example
  File "<stdin>", line 3, in odd
ValueError: 0不能做除数
我们使用了raise关键字,当判断除数为0时
我们就会执行raise所在的语句,
我们在增加点佐料:
def odd(n):
        if n == 0 :
                raise ZeroDivisionError('0不能做除数')
        return  1 / n
def fourth_example(n):
        try:
                print(odd(n))
        except ZeroDivisionError as a:
                print('错误提示:',a)
fourth_example(int(input('请输入一个数字:')))
请输入一个数字:4
0.25
请输入一个数字:0
错误提示: 0不能做除数
我的理解是 raise可以改变错误类型和后面的错误提示的内容
不加raise时的提示信息是:
请输入一个数字:0
错误提示: division by zero
我们再修改一下
def odd(n):
        if n == 0 :
                raise ZeroDivisionError('0不能做除数')
        return  1 / n
def fourth_example(n):
        try:
                print(odd(n))
        except ValueError as a:
                print('错误提示:',a)

fourth_example(int(input('请输入一个数字:')))

请输入一个数字:0
Traceback (most recent call last):
  File "G:/Pyproject/pachong/pachong.py", line 38, in <module>
    fourth_example(int(input('请输入一个数字:')))
  File "G:/Pyproject/pachong/pachong.py", line 34, in fourth_example
    print(odd(n))
  File "G:/Pyproject/pachong/pachong.py", line 30, in odd
    raise ZeroDivisionError('0不能做除数')
ZeroDivisionError: 0不能做除数
结果并没有except里面的语句,只有raise

在工作中我们有时候会这么做:

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

def bar():
    try:
        foo('0')
    except ValueError as e:
        print('ValueError!')
        raise

bar()
运行一下:
Traceback (most recent call last):
ValueError!
  File "G:/Pyproject/pachong/pachong.py", line 52, in <module>
    bar()
  File "G:/Pyproject/pachong/pachong.py", line 47, in bar
    foo('0')
  File "G:/Pyproject/pachong/pachong.py", line 42, in foo
    raise ValueError('invalid value: %s' % s)
ValueError: invalid value: 0

我们会捕获错误在抛出错误,捕获错误目的只是记录一下,
便于后续追踪。但是,由于当前函数不知道应该怎么处理该错误,
所以,最恰当的方式是继续往上抛,让顶层调用者去处理。好比
一个员工处理不了一个问题时,就把问题抛给他的老板,如果他
的老板也处理不了,就一直往上抛,最终会抛给CEO去处理。

因为错误是class,捕获一个错误就是捕获到该class的
一个实例。因此,错误并不是凭空产生的,而是有意创
建并抛出的。Python的内置函数会抛出很多类型的错误
,我们自己编写的函数也可以抛出错误。
如果要抛出错误,首先根据需要,可以定义一个错误的
class,选择好继承关系,然后,用raise语句抛出一个错
误的实例:

class FooError(ValueError):
    pass

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

foo('0')
执行一下:
Traceback (most recent call last):
  File "err_throw.py", line 11, in <module>
    foo('0')
  File "err_throw.py", line 8, in foo
    raise FooError('invalid value: %s' % s)
__main__.FooError: invalid value: 0

最后我们在说一下记录错误,Python内置的logging
模块可以非常容易地记录错误信息:

import logging

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

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

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

main()
print('END')
执行一下:
ERROR:root:division by zero
Traceback (most recent call last):
  File "err_logging.py", line 13, in main
    bar('0')
  File "err_logging.py", line 9, in bar
    return foo(s) * 2
  File "err_logging.py", line 6, in foo
    return 10 / int(s)
ZeroDivisionError: division by zero
END
你会发现,错误后面的语句也可以执行。
通过配置,logging还可以把错误记录到日志
文件里,方便事后排查,这些我们以后都会接触。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值