错误、调试、测试

来源:互联网 发布:姚明身体数据 编辑:程序博客网 时间:2024/06/14 08:13


一、错误处理

使用try except 错误处理机制:

int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError

此外,如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
    print('try...')
    = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo()foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理

记录错误:

使用logging模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# err_logging.py
 
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')

同样是出错,但程序打印完错误信息后会继续执行,并正常退出

抛出错误:

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

1
2
3
4
5
6
7
8
9
10
11
# err_raise.py
class FooError(ValueError):
    pass
 
def foo(s):
    = int(s)
    if n==0:
        raise FooError('invalid value: %s' % s)
    return 10 / n
 
foo('0')

最后,我们来看另一种错误处理的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# err_reraise.py
 
def foo(s):
    = 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()

bar()函数中,我们明明已经捕获了错误,但是,打印一个ValueError!后,又把错误通过raise语句抛出去了,这不有病么?

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


二、调试

断言(assert)  

1
2
3
4
5
6
7
def foo(s):
    = int(s)
    assert n != 0'n is zero!'
    return 10 / n
 
def main():
    foo('0')

assert的意思是,表达式n != 0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错。

如果断言失败,assert语句本身就会抛出AssertionError


logging模块:

1
2
3
4
5
6
import logging
logging.basicConfig(level=logging.INFO)
= '0'
= int(s)
logging.info('n = %d' % n)
print(10 / n)

这就是logging的好处,它允许你指定记录信息的级别,有debuginfowarningerror等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debuginfo就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。


三、测试


一、错误处理

使用try except 错误处理机制:

int()函数可能会抛出ValueError,所以我们用一个except捕获ValueError,用另一个except捕获ZeroDivisionError

此外,如果没有错误发生,可以在except语句块后面加一个else,当没有错误发生时,会自动执行else语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
    print('try...')
    = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用foo()foo()调用bar(),结果bar()出错了,这时,只要main()捕获到了,就可以处理

记录错误:

使用logging模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# err_logging.py
 
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')

同样是出错,但程序打印完错误信息后会继续执行,并正常退出

抛出错误:

因为错误是class,捕获一个错误就是捕获到该class的一个实例。因此,错误并不是凭空产生的,而是有意创建并抛出的。Python的内置函数会抛出很多类型的错误,我们自己编写的函数也可以抛出错误。

如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例:

1
2
3
4
5
6
7
8
9
10
11
# err_raise.py
class FooError(ValueError):
    pass
 
def foo(s):
    = int(s)
    if n==0:
        raise FooError('invalid value: %s' % s)
    return 10 / n
 
foo('0')

最后,我们来看另一种错误处理的方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# err_reraise.py
 
def foo(s):
    = 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()

bar()函数中,我们明明已经捕获了错误,但是,打印一个ValueError!后,又把错误通过raise语句抛出去了,这不有病么?

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


二、调试

断言(assert)  

1
2
3
4
5
6
7
def foo(s):
    = int(s)
    assert n != 0'n is zero!'
    return 10 / n
 
def main():
    foo('0')

assert的意思是,表达式n != 0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错。

如果断言失败,assert语句本身就会抛出AssertionError


logging模块:

1
2
3
4
5
6
import logging
logging.basicConfig(level=logging.INFO)
= '0'
= int(s)
logging.info('n = %d' % n)
print(10 / n)

这就是logging的好处,它允许你指定记录信息的级别,有debuginfowarningerror等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debuginfo就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。


三、测试


原创粉丝点击