热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【Python】错误、调试和测试

链接到错误处理链接到调试链接到单元测试链接到文档测试 【错误处理】小结:遇到错误怎么办?1、不理它。2、捕获它,再抛出。3、捕获并处理错误。 raise不懂如何处理错误就直接抛出(

链接到错误处理

链接到调试

链接到单元测试

链接到文档测试

 

【错误处理】

小结:遇到错误怎么办?

1、不理它。

2、捕获它,再抛出。

3、捕获并处理错误。

 

raise

不懂如何处理错误就直接抛出(raise),交由合适的层次处理,有时候需要自定义错误,但是通常使用Python内置的错误就可以了:

#!/usr/bin/env python3
#
-*- coding: utf-8 -*-
# 自定义的异常
class MyError(Exception):
pass
# 抛出异常的函数
def f():
raise MyError('This is my error!')
# 不处理,继续抛
def f2():
f()
# 不处理,继续抛
def f3():
f2()
print('hi1') # 被打印
f3()
print('hi2') # 不会被打印,因为程序因为出错而终止了

处理机的调用和函数调用的方向刚好相反,因为最终都没有人来处理这个错误,所以错误被一直上抛,直到被Python解释器捕获:

hi1
Traceback (most recent call last):
File
"D:\labs\test.py", line 21, in
File
"D:\labs\test.py", line 18, in f3
File
"D:\labs\test.py", line 14, in f2
File
"D:\labs\test.py", line 10, in f
__main__.MyError: This is my error!

不懂如何处理错误的第二种方式是记录一下再继续抛出,这需要用到“try…except”:

# 自定义的异常
class MyError(Exception):
pass
# 抛出异常的函数
def f():
raise MyError('This is my error!')
# 不处理,继续抛
def f2():
f()
# 不处理,继续抛
def f3():
f2()
print('hi1') # 被打印
try:
f3()
except Exception as e:
print('...mark')
raise # 原样抛出
finally:
print('b')
print('hi2') # 错误没被处理了,程序不再执行

输出:

hi1
...mark
b
Traceback (most recent call last):
File
"D:\labs\test.py", line 23, in
File
"D:\labs\test.py", line 18, in f3
File
"D:\labs\test.py", line 14, in f2
File
"D:\labs\test.py", line 10, in f
__main__.MyError: This is my error!

(可以观察到finally是无论如何都会在最后被执行的!)

 

try…except

错误一般由底层代码抛出,通常是“他人的代码”,所以更经常写的是try…except别人抛出的错误。

那么如何自己来处理错误呢?当位于合适的层次的时候我们用“try…except”来处理错误:

print('hi1') # 被打印
try:
f3()
except Exception as e:
print('a:', e)
finally:
print('b')
print('hi2') # 错误被处理了,程序继续执行

输出情况:

hi1
a: This
is my error!
b
hi2

测试证明except 父类错误就可以捕获子类错误。

在try的内部一但raise了错误,如果有except语句将其捕获,那么try语句块的剩余语句是不会被执行的,因此try语句块要设定合适的范围,而不是一次try大量的语块:

class Error1(Exception):
pass
try:
print('1')
raise Error1('Error1')
print('2') # 不被执行
print('3') # 不被执行
except Exception as e:
print(e)
print('continue execute')

1
Error1
continue execute

 对于捕获多个错误的情况:

并不是多个错误都会被捕获,因为一旦raise了第一个错误,try语句块的程序就不会再继续执行了,所以同时抛出多个错误的情况是不存在的,书写多个except语句只是为了逐级排查最终捕获一个错误!

 

Python的except语句还可以加上else,如果没有错误将会执行else内的语句。

 

logging

#!/usr/bin/env python3
#
-*- coding: utf-8 -*-
import logging
class Error1(Exception):
pass
try:
print('1')
raise Error1('I make a mistake')
print('2') # 不被执行
print('3') # 不被执行
except Exception as e:
print('4')
logging.exception(e)
print('5')
print('continue execute')

1
4
ERROR:root:I make a mistake
Traceback (most recent call last):
File
"test.py", line 10, in
raise Error1('I make a mistake')
Error1: I make a mistake
5
continue execute

今天遇到了一个问题卡了好一会儿:TabError: inconsistent use of tabs and spaces in indentation。原因是混用了空格和tab(可能是copy代码带来的)。最后删掉重输了一遍就解决了。

 

【调试】

debug的方法:

1、print

2、断言:print的升级版。

3、logging:既可以输出到console,也可以输出到文件、不打断程序执行。

在使用logging之前还需要在程序头添加一行配置:

import logging
logging.basicConfig(level
=logging.WARNING)

level指定了记录信息的级别,分为DEBUG、INFO、WARNING、ERROR。当level指定为DEBUG,记录debug及以上的logging信息,当level指定为INFO,记录info及以上的logging信息,以此类推:

import logging
logging.basicConfig(level
=logging.DEBUG)
print(1)
logging.debug(
'debug:hi')
logging.info(
'info:hi')
logging.warning(
'warning:hi')
logging.error(
'error')
print(2)

输出:

1
DEBUG:root:debug:hi
INFO:root:info:hi
WARNING:root:warning:hi
ERROR:root:error
2

继续修改level的等级:

logging.basicConfig(level=logging.INFO)

1
INFO:root:info:hi
WARNING:root:warning:hi
ERROR:root:error
2

…

logging.basicConfig(level=logging.WARNING)

1
WARNING:root:warning:hi
ERROR:root:error
2

…

logging.basicConfig(level=logging.ERROR)

1
ERROR:root:error
2

 

4、pdb

在命令行下开启dubug模式(参数要加在文件名前面) :

$ python -m pdb test.py

输入n单步执行代码:

$ python -m pdb test.py
> d:\labs\test.py(3)()
-> n = 0
(Pdb) n
> d:\labs\test.py(4)()
-> print(1)
(Pdb) n
1
> d:\labs\test.py(5)()
-> n = n + 1
(Pdb)

随时可以用 p 变量名查看变量:

> $ test.py(9)()
-> n = n + 1
(Pdb) p n
2

使用q来退出。

 最后,从某处开始debug的方法:

import pdb print(1)
print(2)
pdb.set_trace()
# 从这里开始进入debug模式。
print(3)
print(4)
print(5)

直接运行.py程序就可以了。

ps:一直执行n命令将循环运行程序。

 

【单元测试】

Q1:什么是单元测试?

Q2:如何进行单元测试?

 

A1:单元测试是指对一个模块、一个函数或者一个类来进行正确性检验的测试。

 

A2:例如我要检测自己写的sum()函数好不好用。

def sum(x, y):
return x + y

1、首先需要编写测试用例,这需要用到Python自带的unittest模块:

import unittest
from test import sum

class TestSum(unittest.TestCase):
def test_func(self):
self.assertEqual(sum(
1, 2), 3)
self.assertEqual(sum(
1, -2), -1)
self.assertEqual(sum(
100, -2), 98)
self.assertEqual(sum(
1001, 110), 1111)

assertEqual是用于判定两个参数是否相等的函数,unittest模块中还有很多用于检测正确性的函数。 凡是test_xxx在测试的时候都会被运行。

import unittest
from test import sum
class TestSum(unittest.TestCase):
def test_func(self):
self.assertEqual(sum(
1, 2), 3)
self.assertEqual(sum(
1, -2), 0)
self.assertEqual(sum(
100, -2), 98)
self.assertEqual(sum(
1001, 110), 1111) def test_func2(self):
self.assertEqual(sum(
1, 2), 3)
self.assertEqual(sum(
1, -2), 0)
self.assertEqual(sum(
100, -2), 90)
self.assertEqual(sum(
1001, 110), 1111)
def test_func3(self):
self.assertEqual(sum(
1, 2), 3)
self.assertEqual(sum(
1, -2), -1)
self.assertEqual(sum(
100, -2), 98)
self.assertEqual(sum(
1001, 110), 1111)
def test_func4(self):
print('hi~')
print('#$@#%@#$^%%#$^@@#$^&*')

 

2、运行测试用例:

$ python -m unittest sum_test.py
.
----------------------------------------------------------------------
Ran
1 test in 0.000s
OK

$ python -m unittest sum_test.py
FF.hi
~
#$@#%@#$^%%#$^@@#$^&*
.
======================================================================
FAIL: test_func (sum_test.TestSum)
----------------------------------------------------------------------
Traceback (most recent call last):
File
"D:\labs\sum_test.py", line 9, in test_func
self.assertEqual(sum(
1, -2), 0)
AssertionError:
-1 != 0
======================================================================
FAIL: test_func2 (sum_test.TestSum)
----------------------------------------------------------------------
Traceback (most recent call last):
File
"D:\labs\sum_test.py", line 15, in test_func2
self.assertEqual(sum(
1, -2), 0)
AssertionError:
-1 != 0
----------------------------------------------------------------------
Ran
4 tests in 0.000s
FAILED (failures
=2)

 有时候可能会期待是不是抛出一些错误,可以这么写:

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

 在测试用例中还可以添加setUp和tearDown函数,这两个函数分别在测试开始时和测试结束时被调用。

 

【文档测试】

1、搭建测试环境。

def sum(x, y):
''' test my sum funtion '''
return x + y
if __name__ == '__main__': import doctest doctest.testmod()

$ python test.py
# 无输出

 

2、编写测试代码

def sum(x, y):
'''
test my sum funtion >>> sum(2, 3) 5 >>> sum(1, 9) 10
'''
return x + y
if __name__ == '__main__':
import doctest
doctest.testmod()

如果代码测试无误就不会有输出。

如果有错则有类似输出如下:

$ python test.py
**********************************************************************
File
"test.py", line 8, in __main__.sum
Failed example:
sum(
1, 9)
Expected:
9
Got:
10
**********************************************************************
1 items had failures:
1 of 2 in __main__.sum
***Test Failed*** 1 failures.

 


推荐阅读
  • java datarow_DataSet  DataTable DataRow 深入浅出
    本篇文章适合有一定的基础的人去查看,最好学习过一定net编程基础在来查看此文章。1.概念DataSet是ADO.NET的中心概念。可以把DataSet当成内存中的数据 ... [详细]
  • Lua字符串1.字符串常见形式字符串或串(String)是由数字、字母、下划线组成的一串字符。Lua语言中字符串可以使用以下三种方式来表示:•单引号间的一串字符。 ... [详细]
  • 版权所有 © 2015 CSDN博客,保留所有权利。本文档详细介绍了使用C语言编写计算圆柱体表面积的程序,包括代码实现及运行结果。 ... [详细]
  • 本文介绍了如何使用Java编程语言实现凯撒密码的加密与解密功能。凯撒密码是一种替换式密码,通过将字母表中的每个字母向前或向后移动固定数量的位置来实现加密。 ... [详细]
  • HDU 2537 键盘输入处理
    题目描述了一个名叫Pirates的男孩想要开发一款键盘输入软件,遇到了大小写字母判断的问题。本文提供了该问题的解决方案及实现方法。 ... [详细]
  • 个人博客:打开链接依赖倒置原则定义依赖倒置原则(DependenceInversionPrinciple,DIP)定义如下:Highlevelmo ... [详细]
  • 本文探讨了在 PHP 的 Zend 框架下,使用 PHPUnit 进行单元测试时遇到的 Zend_Controller_Response_Exception 错误,并提供了解决方案。 ... [详细]
  • Python Selenium WebDriver 浏览器驱动详解与实践
    本文详细介绍了如何使用Python结合Selenium和unittest构建自动化测试框架,重点解析了WebDriver浏览器驱动的配置与使用方法,涵盖Chrome、Firefox、IE/Edge等主流浏览器。 ... [详细]
  • 本文档旨在提供C语言的基础知识概述,涵盖常量、变量、数据类型、控制结构及函数定义等内容。特别强调了常量的不同类型及其在程序中的应用,以及如何正确声明和使用函数。 ... [详细]
  • 探讨如何在给定数组中寻找一个连续子数组,使其和至少达到指定值s,同时确保子数组长度最短。 ... [详细]
  • 本文探讨了Android系统中联系人数据库的设计,特别是AbstractContactsProvider类的作用与实现。文章提供了对源代码的详细分析,并解释了该类如何支持跨数据库操作及事务处理。源代码可从官方Android网站下载。 ... [详细]
  • 本文探讨了在Python中多线程与多进程的性能差异,特别是在处理CPU密集型任务和I/O密集型任务时的表现。由于全局解释器锁(GIL)的存在,多线程在利用多核CPU方面表现不佳,而多进程则能有效利用多核资源。 ... [详细]
  • 来自FallDream的博客,未经允许,请勿转载,谢谢。一天一套noi简直了.昨天勉强做完了noi2011今天教练又丢出来一套noi ... [详细]
  • 本文详细探讨了编程中的命名空间与作用域概念,包括其定义、类型以及在不同上下文中的应用。 ... [详细]
  • 题面:P3178[HAOI2015]树上操作好像其他人都嫌这道题太容易了懒得讲,好吧那我讲。题解:第一个操作和第二个操作本质上是一样的&# ... [详细]
author-avatar
铁血aaaaaaaaaaaaa_295
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有