Python学习笔记(错误、调试和测试)

1、错误处理
     使用try
     Python内置了try...except...finally...的处理机制,用try来试运行代码,如果出错用except来捕获错误,最后如果有finally,就执行finally中的语句。
     例子:
try:
    print('try...')
    r = 10 / 0
    print('result:', r)
except ZeroDivisionError as e:
    print('except:', e)
finally:
    print('finally...')
print('END')
      except如果什么都不写将会捕获所有错误。还可以写多个excpet来捕获不同的错误,如果没有错误发生还可以写else语句。
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')
       使用try...except的好处还有,可以只在主函数中捕获错误,当主函数调用的函数出错时,一样可以捕获到,而不用在所有函数中捕获。
       调用栈
       如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。
       Traceback中从上到下,最下面的是错误的源头。
       记录错误
       我们可以记录错误信息,同时让程序继续运行下去,通过内置的logging模块来纪录错误信息。
# 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')
        程序打印完错误信息后还会继续运行,正常退出。
$ python3 err_logging.py
ERROR:root:division by zero
Traceback (most recent call last):
  File "err_logging.py", line 13in main
    bar('0')
  File "err_logging.py", line 9in bar
    return foo(s) * 2
  File "err_logging.py", line 6in foo
    return 10 / int(s)
ZeroDivisionError: division by zero
END
         抛出错误     
         可以使用raise语句来抛出错误,使用raise时尽量使用python中内助的错误类型。
try:
    10 / 0
except ZeroDivisionError:
    raise ValueError('input error!')
2、调试
     断言
     用于判断一个表达式,在表达式条件为 false 的时候触发异常。
     assert expression等价于
     if not expression:
               raise AssertionError
     assert 后面也可以跟参数assert expression [, arguments],等价于
     if not expression:
               raise AssertionError(arguments)
     例子:
def foo(s):
    n = int(s)
    assert n != 0'n is zero!'
    return 10 / n

def main():
    foo('0')
     启动Python解释器时可以用-O参数来关闭assert。
     logging
     logging不会抛出错误,而且可以输出到文件:
import logging

s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
     默认情况下,logging模块将日志打印到屏幕上(stdout),日志级别为WARNING(即只有日志级别高于WARNING的日志信息才会输出),日志格式如下:
     WARNING :          root           :       warn message
        日志级别 :  Logger实例名称 :   日志消息内容
     日志级别从低到高为:DEBUG、INFO、WARNING、ERROR、CRITICAL。
     可以通过配置logging.basicConfig()来配置日志的显示级别和将日志输出到文件。
import logging
# 通过下面的方式进行简单配置输出方式与日志级别
logging.basicConfig(filename='logger.log'level=logging.INFO)
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
     将日志等级改为INFO,输出到文件logger.log中,可以正常输出日志。
     INFO:root:n = 0
3、单元测试
     引入Pyhon自带的unittest模块,编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。setUp()、tearDown()会在每个测试用例(test开头)之前和之后执行。对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual():
self.assertEqual(abs(-1), 1# 断言函数返回的结果与1相等
     下面是一个例子:
      待测试的类
class Count:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def add(self):
        return self.a+self.b
     测试用例:
import unittest
class TestDemo(unittest.TestCase):

    def setUp(self):
        print("setUp")

    def test_add(self):
        z = Count(2,3)
        self.assertEqual(z.add(),5)

    def test_invid_add(self):
        z = Count(23)
        self.assertNotEqual(z.add(),6)

    def tearDown(self):
        print("tearDown")

if __name__=="__main__":#把测试脚本当成正常的脚本运行
    unittest.main()
       运行测试单元可以在最后加上两行代码:
if __name__=="__main__":#把测试脚本当成正常的脚本运行
    unittest.main()
       或者在运行脚本时加入-m unittest参数:
      $ python -m unittest mydict_test
4、文档测试
     写在文档注释中的代码可以提取并执行,使用doctest模块可以按照交互式命令行的输入和输出来判断测试结果是否正确。有测试异常的时候,可以用...标识中间一段追踪输出。
# mydict2.py
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__(selfkey):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r"'Dict' object has no attribute '%s'" % key)

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

if __name__=='__main__':#命令行直接运行时,会进行文档测试
    import doctest
    doctest.testmod()
     

评论