第八章-错误调试

1 错误处理

1.1 异常捕捉

  在Python中有try..except..else..finally用于捕捉异常和处理异常

  try后面接需要处理异常的语句

  except后面是对异常进行处理的, 具体有两个形式

    1) 方法一

except 异常名字 as e:
    print(e)

    2)方法二

except:
    print("出现异常")

  else是当没有出现异常的时候执行该体内的语句

  finally是不管出不出现异常都会执行

  异常都是继承自BaseException

  except可以有多个, 但是顺序很重要, 如果前面的是父类的异常, 那么在之后的子类的异常就处理不到了

  因此先写类型小的异常, 再写类型大的异常

  具体的异常的继承关系

  try..except还可以捕捉该语句块中可以出现调用关系内某个语句发生的异常

  具体的演示实例如下

try:
    print('try...')
    r = 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')

1.2 抛出异常

  有的时候异常不一定非要在本位置处理, 可以抛出异常给上一级处理

  抛出异常用raise

  具体的使用方法

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

  另外在抛出异常之后, 可以在接受位置处理异常, 这样并不是冗余重复, 有的是为了集中处理异常

1.3 记录错误

  可以通过logging模块来讲错误信息保存在日志文件中

  这样函数不仅记录了错误信息, 程序就算发生了异常也可以正常运行

  具体使用格式

import logging
...
logging.exception(异常对象)

  具体代码如下

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

2 调试

2.1 断言

  断音使用关键字assert

  断言后面跟一个判断表达式

  判断表达式为True表示能够正常执行, 为False就会出现AssertionError异常

  断言判断表达式后面可以接一个提示信息, 用于出现异常的情况, 将该信息放到AssertionError后, 这俩之间用逗号分隔

  具体格式如下

assert 判断表达式, 异常提示字符串

  如果assert过多, 可以在执行py文件的时候加入-o参数来忽略断言

python3 -O py文件

2.2 logging

  在logging模块中还可以记录不同级别的信息

  logging的信息有debug, info, warning, error四种级别的信息

  可以通过

logging.basicConfig(level=logging.级别名字)

  来指定输出的级别信息, 设置之后在该级别前面的级别的信息就不起作用了

3 单元测试

  单元测试是一种测试驱动开发的模式

  可以确保程序模块符合测试用例

  在模块修改的时候也可以在重新运行一下单元测试, 很方便

  Python中的unittest模块就是编写单元测试的

  单元测试的类名, 方法名(尤其是)都最好是以test开头

  测试的类需要继承 unittest.TestCase

  继承之后会有两个特殊地函数 setUp() 和 tearDown() 函数

  这两个函数分别是在测试前和测试后执行

  主要适用于在开始前后的准备和结束代码

  下面是模拟dict的代码

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

  下面是测试该代码的单元测试

import unittest

from mydict import Dict

class TestDict(unittest.TestCase):

    def setUp(self):
        print('setUp...')

    def tearDown(self):
        print('tearDown...')

    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()
        with self.assertRaises(KeyError):
            value = d['empty']

    def test_attrerror(self):
        d = Dict()
        with self.assertRaises(AttributeError):
            value = d.empty

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

4 文档测试

  在定义某些类的时候, 可以通过'''说明信息'''来形成__doc__

  可以在该部分写入一些测试代码, 类似于交互式环境的代码

  通过Python内置的文档测试, 可以运行那些测试代码, 来更加快速的检验代码的正确性

  具体写入的代码中如果输出结果较多, 可以用...来代替

  具体如下

class Dict(dict):
    '''
    Simple dict but also support access as x.y style.

    >>> d1 = Dict()
    >>> d1['x'] = 100
    >>> d1.x
    100
    >>> d1.y = 200
    >>> d1['y']
    200
    >>> d2 = Dict(a=1, b=2, c='3')
    >>> d2.c
    '3'
    >>> d2['empty']
    Traceback (most recent call last):
        ...
    KeyError: 'empty'
    >>> d2.empty
    Traceback (most recent call last):
        ...
    AttributeError: 'Dict' object has no attribute 'empty'
    '''
    def __init__(self, **kw):
        super(Dict, self).__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

if __name__=='__main__':
    import doctest
    doctest.testmod()

  运行该代码后如果没有输出, 则一切正常

  文档测试只会在命令直接运行时才会执行, 正常导入模块是不会执行的

 

posted @ 2017-04-18 22:44  weihuchao  阅读(194)  评论(0编辑  收藏  举报