【Pyhton学习】错误、调试和测试

(一)错误处理

在程序运行的过程中,如果发生了错误,可以事先约定返回一个错误代码,这样,就可以知道是否有错,以及出错的原因。所以高级语言通常都内置了一套try...except...finally...的错误处理机制:

try

# try
try:
    print("try...")
    n = 20 / 0
    print("result:", n)
except ZeroDivisionError as e:
    print("except:", e)
finally:
    print("finally...")
print('END')
try...
except: division by zero
finally...
END

当某些代码可能会出错时,就可用try来运行这段代码,如果执行出错,则后续代码不会继续执行,而是直接跳转至错误处理代码,即except句块,执行完except后,如果有finally语句块,则执行finally语句块,至此,执行完毕。Python的错误其实也是class,所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,它不但捕获该类型的错误,还把其子类也“一网打尽”。

使用try...except捕获错误还有一个巨大的好处,就是可以跨越多层调用,比如函数main()调用f()f()调用b(),结果b()出错了,这时,只要main()捕获到了,就可以处理。不需要在每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误就可以。

def f(s):
    return 10 / int(s)

def b(s):
    return f(s) * 2

def main():
    try:
        b('0')
    except Exception as e:
        print('Error:',e)
    finally:
        print('finally...')

main()

调用栈

如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。出错的时候,一定要分析错误的调用栈信息,才能定位错误的位置。

记录错误

如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
Python内置的logging模块可以非常容易地记录错误信息:

# err_logging.py
import logging
def f(s):
    return 10 / int(s)

def b(s):
    return f(s) * 2

def main():
    try:
        b('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')
ERROR:root:division by zero
Traceback (most recent call last):
  File "demo.py", line 40, in main
    b('0')
  File "demo.py", line 36, in b
    return f(s) * 2
  File "demo.py", line 33, in f
    return 10 / int(s)
ZeroDivisionError: division by zero
END

通过配置,logging可以把错误记录到日志文件里。

抛出错误

因为错误是class,捕获一个错误就是捕获到该class的一个实例。如果要抛出错误,首先根据需要,可以定义一个错误的class,选择好继承关系,然后,用raise语句抛出一个错误的实例。

class FoErr(ValueError):
    pass

def fo(s):
    n = int(s)
    if n == 0:
        raise FoErr('invalid value:%s' % s)
    return 10 / n

fo(0)
Traceback (most recent call last):
  File "demo.py", line 62, in <module>
    fo(0)
  File "demo.py", line 58, in fo
    raise FoErr('invalid value:%s' % s)
__main__.FoErr: invalid value:0

(二)调试

程序有Bug,需要一整套调试程序的手段来修复Bug。

  • 第一种:print()把可能出问题的变量打出来
def foo(s):
    n = int(s)
    print('n = %d' % n)
    return 10 / n

def main():
    foo('0')

main()

执行后在输出中查找打印的变量值:

n = 0
Traceback (most recent call last):
	...
ZeroDivisionError: division by zero

不建议使用print()

  • 第二种:断言 assert
    assert的意思是,表达式n != 0应该是True,否则,根据程序运行的逻辑,后面的代码肯定会出错。
    如果断言失败,assert语句本身就会抛出AssertionError
def foo(s):
    n = int(s)
    assert n != 0, 'n = 0'
    return 10 / n

def main():
    foo('0')

main()
Traceback (most recent call last):
  ...
AssertionError: n = 0

启动Python解释器时可以用-O参数来关闭assert,关闭后,所有的assert语句当成pass来看。

  • 第三种:logging
    logging不会抛出错误,而且可以输出到文件
import logging

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 "err.py", line 31, in <module>
    print(10 / n)
ZeroDivisionError: division by zero

logging的好处,允许你指定记录信息的级别,有debug,info,warning,error等几个级别。可以放心地输出不同级别的信息,不用删除,最后统一控制输出哪个级别的信息。通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。

  • 第四种:IDE设置断点

单元测试

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
unittest模块:提供一整套的测试框架单元测试框架

  • 测试脚手架
    test fixture 表示为了开展一项或多项测试所需要进行的准备工作,以及所有相关的清理操作。举个例子,这可能包含创建临时或代理的数据库、目录,再或者启动一个服务器进程。

  • 测试用例
    一个测试用例是一个独立的测试单元。它检查输入特定的数据时的响应。 unittest 提供一个基类: TestCase ,用于新建测试用例。

  • 测试套件
    test suite 是一系列的测试用例,或测试套件,或两者皆有。它用于归档需要一起执行的测试。

  • 测试运行器(test runner)
    test runner 是一个用于执行和输出测试结果的组件。这个运行器可能使用图形接口、文本接口,或返回一个特定的值表示运行测试的结果。

1、TestCase类:
在这里插入图片描述
多函数多用例测试:

import unittest  # 导入测试模块


def showMsg(msg):
    return '%s' % msg


def do_divdie(a, b):
    return a / b


def showTrue(flag):
    return flag


class TestSomeFunc(unittest.TestCase):  # 自定义测试类 继承unittest.TestCase
    def testrun(self):  # 自定义测试方法
        self.assertEqual('MC', showMsg('MC'))
        self.assertNotEqual('OK', showMsg('NO'))
        self.assertTrue(do_divdie(1, 2))  # 测试结果值是否为True
        self.assertIs(showTrue(False), False)  # 测试预期值与函数结果是否一致
        self.assertIs(int(do_divdie(1, 2)), 1)  # 测试预期值与函数结果是否一致


if __name__ == '__main__':
    unittest.main()  # 调用mian方法自动执行测试用例

测试结果:

F																# 出错信息提醒
======================================================================
FAIL: testrun (__main__.TestSomeFunc)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "单元测试.py", line 22, in testrun		# 22行代码,执行结果和预期不一致
    self.assertIs(int(do_divdie(1, 2)), 1)
AssertionError: 0 is not 1							#结果0不符合预期值1

----------------------------------------------------------------------
Ran 1 test in 0.000s									# 测试所用时间

FAILED (failures=1)									#一项测试失败

文档测试

doctest对所编写的代码当做文档字符串进行读取,然后通过相应的测试规则,对所编写的代码进行自动测试。doctest不但可以用来测试,还可以直接作为示例代码。通过某些文档生成工具,就可以自动把包含doctest的注释提取出来。用户看文档的时候,同时也看到了doctest

  • 1、嵌入代码测试
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()

什么输出也没有。说明编写的doctest运行都是正确的。将数字200加上' ',就会报错:

**********************************************************************
File "文档测试.py", line 10, in __main__.Dict
Failed example:
    d1['y']
Expected:
    200
Got:
    '200'
**********************************************************************
1 items had failures:
   1 of   9 in __main__.Dict
***Test Failed*** 1 failures.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
众所周知,人工智能是当前最热门的话题之一, 计算机技术与互联网技术的快速发展更是将对人工智能的研究推向一个新的高潮。 人工智能是研究模拟和扩展人类智能的理论与方法及其应用的一门新兴技术科学。 作为人工智能核心研究领域之一的机器学习, 其研究动机是为了使计算机系统具有人的学习能力以实现人工智能。 那么, 什么是机器学习呢? 机器学习 (Machine Learning) 是对研究问题进行模型假设,利用计算机从训练数据中学习得到模型参数,并最终对数据进行预测和分析的一门学科。 机器学习的用途 机器学习是一种通用的数据处理技术,其包含了大量的学习算法。不同的学习算法在不同的行业及应用中能够表现出不同的性能和优势。目前,机器学习已成功地应用于下列领域: 互联网领域----语音识别、搜索引擎、语言翻译、垃圾邮件过滤、自然语言处理等 生物领域----基因序列分析、DNA 序列预测、蛋白质结构预测等 自动化领域----人脸识别、无人驾驶技术、图像处理、信号处理等 金融领域----证券市场分析、信用卡欺诈检测等 医学领域----疾病鉴别/诊断、流行病爆发预测等 刑侦领域----潜在犯罪识别与预测、模拟人工智能侦探等 新闻领域----新闻推荐系统等 游戏领域----游戏战略规划等 从上述所列举的应用可知,机器学习正在成为各行各业都会经常使用到的分析工具,尤其是在各领域数据量爆炸的今天,各行业都希望通过数据处理与分析手段,得到数据中有价值的信息,以便明确客户的需求和指引企业的发展。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值