热门标签 | 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.

 


推荐阅读
  • 在Python多进程编程中,`multiprocessing`模块是不可或缺的工具。本文详细探讨了该模块在多进程管理中的核心原理,并通过实际代码示例进行了深入分析。文章不仅总结了常见的多进程编程技巧,还提供了解决常见问题的实用方法,帮助读者更好地理解和应用多进程编程技术。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • Spring框架中的面向切面编程(AOP)技术详解
    面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。Spring AOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
  • Java集合框架特性详解与开发实践笔记
    Java集合框架特性详解与开发实践笔记 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 本文探讨了Android系统中支持的图像格式及其在不同版本中的兼容性问题,重点涵盖了存储、HTTP传输、相机功能以及SparseArray的应用。文章详细分析了从Android 10 (API 29) 到Android 11 的存储规范变化,并讨论了这些变化对图像处理的影响。此外,还介绍了如何通过系统升级和代码优化来解决版本兼容性问题,以确保应用程序在不同Android版本中稳定运行。 ... [详细]
  • 本文介绍了一种利用Dom4j库和JFileChooser组件在Java中实现XML文件自定义路径导出的方法。通过创建一个Document对象并设置根元素,结合JFileChooser选择目标路径,实现了灵活的XML文件导出功能。具体步骤包括初始化Document对象、构建XML结构以及使用JFileChooser选择保存路径,确保用户能够方便地将生成的XML文件保存到指定位置。 ... [详细]
  • Node.js 配置文件管理方法详解与最佳实践
    本文详细介绍了 Node.js 中配置文件管理的方法与最佳实践,涵盖常见的配置文件格式及其优缺点,并提供了多种实用技巧和示例代码,帮助开发者高效地管理和维护项目配置,具有较高的参考价值。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • CentOS 7环境下Jenkins的安装与前后端应用部署详解
    CentOS 7环境下Jenkins的安装与前后端应用部署详解 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 利用CSV Data Set Config实现JMeter参数化测试的详细指南
    本文详细介绍了如何使用JMeter中的CSV Data Set Config元素来实现参数化测试。通过该配置元件,用户可以轻松地从外部CSV文件中读取数据,从而提高测试的灵活性和可扩展性。文章不仅提供了具体的配置步骤,还结合实际案例,展示了如何在不同的测试场景中应用这一功能,帮助读者更好地理解和掌握JMeter参数化测试的技巧。 ... [详细]
  • 开发笔记:深入解析Android自定义控件——Button的72种变形技巧
    开发笔记:深入解析Android自定义控件——Button的72种变形技巧 ... [详细]
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社区 版权所有