python学习(八) 错误、调试和测试

错误处理

  • try...except...finally...的错误处理机制。

try

# 可以有多个except来捕获不同类型的错误
# 没有错误发生,可以在except语句块后面加一个else
# 捕获该类型的错误及其所有子类
try:
    print('try...')
    r = 10 / int('a')
    print('result:', r)
except ValueError as e: 
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
finally:
    print('finally...')
print('END')
  • 所有的错误都是从BaseException类派生。
  • try...except可以跨越多层调用。

调用栈

  • 如果错误没有被捕获,会一直往上抛,最后被解释器捕获,打印错误信息,程序退出。
  • 分析错误调用栈信息,能定位错误位置。

记录错误

  • 内置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')

抛出错误

  • 错误是class,捕获一个错误就是捕获一个实例。
  • 根据需要定义一个错误的class,选择好继承关系,用raise语句抛出一个错误的实例。
  • 捕获错误,打印错误内容后,又把错误通过raise语句抛出,让顶层调用者去处理。
  • raise不带参数——当前错误原样抛出。
  • exceptraise一个Error,可把错误类型转化成另一种类型。

调试

  • print()把可能有问题的变量打印出来看看,运行结果会包含很多垃圾信息。

断言

  • print()辅助查看地方,都可用断言(assert)来替代。
def foo(s):
    n = int(s)
    assert n != 0, 'n is zero!'
    return 10 / n

def main():
    foo('0')
  • 断言失败,assert语句会抛出AssertionError
  • -O参数来关闭assert关闭后,所有的assert语句当成pass

logging

  • print()替换为logging,和assert比,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)

pdb

  • 让程序以单步方式运行,可以随时查看运行状态。

pdb.set_trace()

  • 不需要单步执行,import pdb后,可能出错地方放pdb.set_trace(),即设置一个断点。

IDE(Integrated Development Environment )

单元测试

  • 对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
class Dict(dict):

    def __init__(self, **kw):
        super().__init__(**kw)

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value

# 编写单元测试,需要引入Python自带的unittest模块

import unittest

from mydict import Dict

class TestDict(unittest.TestCase):
# 以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行
# unittest.TestCase提供了很多内置的条件判断,只需要调用这些方法就可以断言输出是否是期望的。
# 最常用的断言就是assertEqual()
    def test_init(self):
        d = Dict(a=1, b='test')
        self.assertEqual(d.a, 1)
        self.assertEqual(d.b, 'test')
        self.assertTrue(isinstance(d, dict))

    def test_key(self):
        d = Dict()
        d['key'] = 'value'
        self.assertEqual(d.key, 'value')

    def test_attr(self):
        d = Dict()
        d.key = 'value'
        self.assertTrue('key' in d)
        self.assertEqual(d['key'], 'value')

    def test_keyerror(self):
        d = Dict()
        # 期待抛出指定类型的Error,比如通过d['empty']访问不存在的key时,断言会抛出KeyError
        with self.assertRaises(KeyError):
            value = d['empty']

    def test_attrerror(self):
        d = Dict()
        # 通过d.empty访问不存在的key时,我们期待抛出AttributeError
        with self.assertRaises(AttributeError):
            value = d.empty

运行单元测试

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

setUp与tearDown

  • 编写两个特殊的setUp()tearDown()方法,会分别在每调用一个测试方法的前后被执行。

文档测试

def abs(n):
    '''
    Function to get absolute value of number.
    
    Example:
    
    >>> abs(1)
    1
    >>> abs(-1)
    1
    >>> abs(0)
    0
    '''
    return n if n >= 0 else (-n)
  • 内置“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。
  • 当模块正常导入时,doctest不会被执行。只有在命令行直接运行时,才执行doctest
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值