【廖雪峰Python学习笔记】错误、调试、测试


错误类型

  1. 程序编写问题bug – 字符类型错误等
  2. 用户输入错误 – 输入不符合规定的字符串
  3. 异常,程序运行时无法预测 – 磁盘满了,无法写

错误处理

错误处理机制:try…except…finally…

  1. try运行可能会出错的代码,若出错则后续代码不再运行
  2. try中存在错误代码时,执行except语句块抛出异常
  3. finally可有可无,不论是否异常,最后都会执行
  4. 所有错误类型均继承自BaseException
  5. 不同except可以对不同错误类型进行处理
  6. except可以捕获自身及子类的错误
  7. except可以跨越多层调用
try:
	print('try...')
	test_int = 10 / int('a')				# 除法运算错误
	print('result = ', test_int)			# 由于上一行代码错误,try的后续代码不再运行
except ZeroDivisionError as e:		
	print('except: ', e)
except ValueError as e:
    print('ValueError:', e)
elseprint('no error was found!')
finally:
	print('finally...')
print('END')

调用栈:出错时,须分析错误的调用栈信息,以定位错误的位置

Traceback (most recent call last):
	……
	……

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()

输出结果:

ERROR:root:division by zero
Traceback (most recent call last):
  File "/Pratice/DEMO.py", line 8, in main
    bar('0')
  File "/Pratice/DEMO.py", line 5, in bar
    return foo(s) * 2
  File "/Pratice/DEMO.py", line 3, in foo
    return 10 / int(s)
ZeroDivisionError: division by zero

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 "/Pratice/DEMO1.py", line 14, in <module>
    bar()
  File "/Pratice/DEMO1.py", line 9, in bar
    foo('0')
  File "/Pratice/DEMO1.py", line 4, in foo
    raise ValueError('invalid value: %s' % s)
ValueError: invalid value: 0

调试

使用print()调试,简单粗暴,但是调试过后需要删除调试代码

  1. assert()断言
def foo(s):
	n = int(s)
	assert n != 0, 'n is zero'	# 若‘n != 0’不成立,则抛出AssertionError
	return 10/s
	
def main():
	foo('0')
main()
	输出结果:
Traceback (most recent call last):
  File "/Pratice/DEMO2.py", line 8, in <module>
    main()
  File "/Pratice/DEMO2.py", line 7, in main
    foo('0')
  File "/Pratice/DEMO2.py", line 3, in foo
    assert n != 0, 'n is zero'
AssertionError: n is zero

tips:python -O DEMO2.py 可以将DEMO2.py中的assert当成pass来看
2. logging()记录
输出文件而不是抛出错误
可指定记录信息的级别
通过简单配置,一条语句可同时输出到不同地方

import logging
# 指定记录信息的级别 debug->info->warning->error
logging.basicConfig(level=logging.INFO)	

s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)

输出结果:

INFO:root:n = 0
Traceback (most recent call last):
  File "/Pratice/DEMO3.py", line 7, in <module>
    print(10 / n)
ZeroDivisionError: division by zero
  1. pdb调试器
    让程序以单步方式运行,随时查看运行状态
➜  python -m pdb DEMO.py	# 使用调试器查看单步运行状态
> /Users/amey/growingio/Pratice/DEMO.py(1)<module>()
-> import logging
(Pdb) l								# l查看代码
  1  -> import logging
  2     logging.basicConfig(level=logging.INFO)
  3     
  4     s = '0'
  5     n = int(s)
  6     logging.info('n = %d' % n)
  7     print(10 / n)
[EOF]
(Pdb) n								# n -> 单步执行代码
> /Users/amey/growingio/Pratice/DEMO.py(2)<module>()
-> logging.basicConfig(level=logging.INFO)
(Pdb) n								# n -> 单步执行代码
> /Users/amey/growingio/Pratice/DEMO.py(4)<module>()
-> s = '0'
(Pdb) p s							# p 变量名 -> 查看变量
> '0'
(Pdb) q								# q -> 结束调试

单元测试unitcase

  1. setUp()tearDown()方法,在调用一个测试方法前后分别执行
    [eg:连接关闭数据库]
  2. 使用python -m unittest test可以批量运行多个单元测试

编写一个学生成绩单元测试

import unittest

class Student(object):
    def __init__(self, name ,score):
        self.name = name
        self.score = score

    def get_grade(self):
        if(self.score > 100 or self.score < 0 or type(self.score) != int):
            raise ValueError
        elif(self.score < 60):
            return 'C'
        elif(self.score < 80):
            return 'B'
        else:
            return 'A'

class TestStudent(unittest.TestCase):
    def test_80_to_100(self):
        s1 = Student('Amey', 100)
        s2 = Student('Jimmy', 80)
        self.assertEqual(s1.get_grade(),'A')
        self.assertEqual(s2.get_grade(),'A')

    def test_60_to_800(self):
        s1 = Student('Bart', 79)
        s2 = Student('Cindy', 60)
        self.assertEqual(s1.get_grade(),'B')
        self.assertEqual(s2.get_grade(),'B')

    def test_0_to_60(self):
        s1 = Student('Dan', 59)
        s2 = Student('Lisa', 0)
        self.assertEqual(s1.get_grade(),'C')
        self.assertEqual(s2.get_grade(),'C')

    def test_invaild(self):
        s1 = Student('Jan', 101)
        s2 = Student('King', -1)
        with self.assertRaises(ValueError):
            s1.get_grade()
        with self.assertRaises(ValueError):
            s2.get_grade()

if __name__ == '__main__':
    unittest.main()

测试结果:

➜ python -m unittest DEMO4   
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

文档测试

doctest模块:可提取注视中的代码并执行测试

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
def fact(n):
    '''
    计算 1*2*3*...*n
    >>> fact(1)
    1
    >>> fact(-1)
    Traceback (most recent call last):
    File "/Pratice/demo.py", line 13, in <module>
        print(fact(-1))
    File "/Pratice/demo.py", line 7, in fact
        raise ValueError
    ValueError
    >>> fact(10)
    3628800
    '''
    if(n < 1):
        raise ValueError
    if(n == 1):
        return 1
    return n * fact(n-1)

if __name__ == '__main__':
    import doctest
    doctest.testmod()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值