错误、调试、测试



一、错误处理

使用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就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。


三、测试


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值