python程序设计基础:异常处理结构与程序调试、测试

本文主要是介绍python程序设计基础:异常处理结构与程序调试、测试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第八章:异常处理结构与程序调试、测试

简单地说,异常是指程序运行时引发的错误,引发错误的原因有很多例如除零、下标越界、文件不存在、网络异常、类型错误、名字错误、字典键错误、磁盘空间不足,等等。

如果这些错误得不到正确的处理将会导致程序终止运行,而合理地使用异常处理结果可以使得程序更加健壮,具有更强的容错性,不会因为用户不小心的错误输入或其他运行时原因而造成程序终止。

也可以使用异常处理结构为用户提供更加友好的提示

程序出现异常或错误之后是否能够调试程序并快速定位和解决存在的问题也是程序员综合水平和能力的重要体现方式之一。

异常的常见表现形式

>x,y=10,5
>a=x/y
>A
Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    A
NameError: name 'A' is not defined. Did you mean: 'a'?

>10*(1/0)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    10*(1/0)
ZeroDivisionError: division by zero

>4+spam*3
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    4+spam*3
NameError: name 'spam' is not defined

>'2'+2
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    '2'+2
TypeError: can only concatenate str (not "int") to str

>fp=open('123.data','rb')
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    fp=open('123.data','rb')
FileNotFoundError: [Errno 2] No such file or directory: '123.data'

8.1基本概念

语法错误逻辑错误不属于异常,但有些语法错误往往会导致异常,例如由于大小写拼写错误而访问不存在的对象。

异常是指因为程序出错而在正常控制流以外采取的行为。当Python检测到一个错误时,解释器就会指出当前流已法继续执行下去,这时候就出现了异常。

异常分为两个阶段:第一个阶段是引起异常发生的错误;第二个阶段是检测并处理阶段。

当程序出现错误,python会自动引发异常,也可以通过raise显式地引发异常。

异常处理的作用

  • 提高程序的健壮性和容错性能
  • 把晦涩难懂的错误提示转换为友好提示显示给最终用户

注意

  • 不建议使用异常来代替常规的检查,如if ... else判断。
  • 应避免过多使用异常处理机制,只在确实需要时才使用。
  • 捕捉异常时,应尽量精准,并针对不同类型的异常设计不同的处理代码。

8.2python中的异常类

内建异常类的层次结构

可以继承python内置异常类来实现自定义的异常类

#实现自定义的异常类
class SHortInputException(Exception):#length:长度,atleast:最小的长度def__init__(self,length,atleast):Exception.__init__(self)self.length=lengthself.atleast=atleasttry:s=input('请输入-->')#如果输入的长度小于3if len(s)<3:#显式抛出这样的异常raise ShortInputException(len(s),3)#遇到的是end of false
except EOFError:print('你输入了一个结束标记EOF')#遇到的是上面我们自定义的异常
except ShortInputException as x:print('ShortInputException:长度是%d,至少应是%d'%(x.length,x.atleast))else:print('没有异常发生。')

再例如

>class MyError(Exception):
    def __init__(self,value):
        self.value=value
    def __str__(self):
        return repr(self.value)

    
>try:
    raise MyError(2*2)
except MyError as e:
    print('My exception occurred,value:',e.value)

    
My exception occurred,value: 4
 

如果自己编写的某个模块需要抛出多个不同的异常,可以先创建一个基类,再创建多个派生类分别表示不同的异常。

class Error(Exception):
        pass

class InputError(Error):
        def init_(self, expression, message):
                self.expression = expression
                self.message = message

class TransitionError(Error):
        def init_(self, previous, next, message):
                self.previous = previous
                self.next = next
                self.message = message

8.3常见的异常处理结构

8.3.1try..except结构

try子句中的代码块放置可能出现异常的语句,except子句中的代码块处理异常。

try:

        try块        #被监控的语句

except Exception[ as reason]:

        except块        #捕获异常,处理异常的语句

BaseException用使以可,时常异有所获捕要需 当

try:

        try块

except BaseException as e:        #不要使用异常的基类捕获异常,会捕获所有的异常;不建议这样做

        except块...        #没办法精准的处理;处理所有错误

要求用户必须输入数字字符串

>while True:
    x=input('Please input:')        #请输入
    try:
        x=int(x)        #int转换成功
        print('You have input {0}'.format(x))
        break
    except Exception as e:        #int转换错误,捕获异常
        print('Error.')        #输出

Please input:2
You have input 2

except子句可以在异常类名字后面指定一个变量

>try:
    raise Exception('spam','eggs')
except Exception as inst:        #给异常指定变量as,通过变量获取更加详细的信息
    print(type(inst))
    print(inst.args)
    print(inst)
    x,y=inst.args
    print('x=',x)
    print('y=',y)

    
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x= spam
= eggs

8.3.2try...except..else

如果try范围内捕获了异常,就执行except块;如果try范围内没有捕获异常,就执行else块。

#try...except...else
#定义一个列表
a_list=['China','America','England','France']
#死循环
while True:#获取字符串n=input('请输入字符串的序号:')try:#尝试把输入的内容转换成整数n=int(n)#如果能转换成整数,就输出print(a_list[n])#下边越界except IndexError:print('列表元素的下标越界,请重新输入字符串的序号')#没有异常,就执行breakelse:break

查看多个文本文件分别有多少行

#加入前面给了多个文件
for arg in sys.args[1:]:try:#尝试打开遍历到文件f=open(arg,'r')except IOError: #文件打开失败print('cannot open',arg)#打开成功,执行else后面的语句else:#输出这个文件里面有多少行print(arg,'has',len(f.readlines()),'lines')#关闭文件f.close()

要求用户必须输入整数的代码也可以这样写

>while True:
    x=input('Please input:')
    try:
        x=int(x)        #转换成数字,没有问题执行else
    except Exception as e:        #有问题,输出Error
        print('Error.')
    else:
        print('You have input{0}'.format(x))
       break

8.3.3带有多个except的try结构

可能出现多种不同的异常,用多个except捕获

try:

        try块        #被监控的语句

except Exception1:

        except块1        #处理异常1的语句

except Exception2:

        except块2          #处理异常2的语句

例如:

#用多个except捕获
try:#下面三行代码没问题,执行else后的语句x=input('请输入被除数:')y=input('请输入除数:')z=float(x)/float(y)
except ZeroDivisionError:print('除数不能为零')
except TypeError:print('被除数和除数应该为数值类型')
except NameError:print('变量不存在')
else:print(x,'/',y,'=',z)

再例如:

import sys
try:f=open('myfile.txt')s=f.readline()i=int(s.strip)f.close()
except OSError as err:print("OS error:{0}".format(err))
except ValueError:print("Cloud not convert data to an integer.")
except:print("Unexcept error:",sys.exc_info()[0])raise

将要捕获的异常写在一个元组中,可以使用一个except语句捕获多个异常

#使用一个except语句捕获多个异常
import sys
try:f=open('myfile.txt')s=f.readline()i=int(s.strip())f.close()
except (OSError,ValueError,RuntimeError,NameError):pass

8.3.4try...except...finally结构

在该结构中,finally子句中的内存无论是否发生异常都会执行,常用来做一些清理工作以释放try子句中申请的资源。

try:

        ......

finally:
        ......        #乌无论如何都会执行

try:
    3/0
except:        #出错,用except捕获,会输出一个3
    print(3)
finally:        #执行完except后,执行finally,输出5;不管前面有没有错,finally都会执行
    print(5)

    
3
5
 

使用异常处理结构保证文件总是能关闭

#使用异常处理结构保证文件总是能关闭
>try:
    f=open('test.txt','r')
    line=f.readline()
    print(line)
finally:
    f.close()

上面的代码,使用异常处理结构的本意是为了防止文件读取操作出现异常而导致文件不能正常关闭,但是如果因为文件不存在而导致文件对象创建失败,那么finally子句中关闭文件对象的代码将会抛出异常从而导致程序终止运行。

如果try子句中的异常没有被处理,或者在except子句或else子句中出现了异常,那么这些异常将会在finally子句执行完后再次抛出。

>try:
    3/0
finally:
    print(5)

    
5
Traceback (most recent call last):
  File "<pyshell#13>", line 2, in <module>
    3/0
ZeroDivisionError: division by zero
 

例如,有函数定义如下:

>def divide(x,y):
    try:
        result=x/y
    except ZeroDivisionError:
        print("division by zero")
    #上面没有问题,执行else
    else:
        print("result is",result)
    #最后在执行个finally
    finally:
        print("executing fianlly clause")

>divide(2,1)
result is 2.0
executing fianlly clause

>divide(2,0)
division by zero
executing fianlly clause

>divide("2","1")        #没有考虑到传递的参数是字符串类型,执行完finally后会抛出异常
executing fianlly clause
Traceback (most recent call last):
  File "<pyshell#27>", line 1, in <module>
    divide("2","1")
  File "<pyshell#23>", line 3, in divide
    result=x/y
TypeError: unsupported operand type(s) for /: 'str' and 'str'

使用带有finally子句的异常处理结构时,应尽量避免在finally子句中使用return语句,否则可能会出现出乎意料的错误。

>def demo_div(a,b):
    try:
        return a/b
    except:
        pass
    finally:
        return -1

    
>demo_div(1,0)
-1
>demo_div(1,2)
-1

8.3.5try...except...except...else...finally

Python异常处理结构中可以同时包含多个except子句、else子句和finally子句。

>def div(x,y):
    try:
        print(x/y)
    except ZeroDivisionError:
        print('ZeroDivisionError')
    except TypeError:
        print('TypeError')
    else:
        print('No Error')
    finally:
        print('executing finally clause')

8.4断言与上下文管理

断言与上下文管理是两种比较特殊的异常处理方式,在形式上比异常处理结构要简单一些。

8.4.1断言

assert expression [, reason]

#expression成立,什么事情都没有;不成立,抛出reason

当判断表达式expression为真时,什么都不做;如果表达式为假,则抛出异常。

assert语句一般用于开发程序时对特定必须满足的条件进行验证,仅当__debug__为True时有效。当Python脚本以-O选项编译为字节码文件时,assert语句将被移除以提高运行速度。

>a=3
>b=5
>assert a==b,'a must be equal to b'
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    assert a==b,'a must be equal to b'
AssertionError: a must be equal to b

>try:
    assert a==b,'a must be equal to b'
except AssertionError as reason:
    print('%s:%s'%(reason.__class__.__name__,reason))

    
AssertionError:a must be equal to b

8.4.2上下文管理语句

使用with自动关闭资源,可以在代码块执行完毕后还原进入该代码块时的现场。

不论何种原因跳出with块,不论是否发生异常,总能保证文件被正确关闭,资源被正确释放。

with语句的语法如下:

with context_expr [as var]:
        with块

>with open('file.txt') as f:
    for line in f:
        print(line,end="")

8.5用sys模块回溯最后的异常

当发生异常时,Python会回溯异常,给出大量的提示,可能会给程序员的定位和纠错带来一定的困难,这时可以使用sys模块来回溯最近一次异常。

>import sys        #导入sys模块
>try:        #尝试去运行代码
    block
except:        #如果出错,except
    tuple=sys.exc_info()        #sys.exc_info():获取异常的信息
    print(tuple)

#sys.exc_info()的返回值tuple是一个元组(type,value,traceback)

#type:异常的类型
#value:异常的信息或者参数(异常的对象)
#traceback:包含调用栈信息的对象

>1/0
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    1/0
ZeroDivisionError: division by zero


>import sys
>try:
    1/0
except:
    r=sys.exc_info()
    print(r)

    
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x000002B49128F3C0>)

#<class 'ZeroDivisionError'>:异常类(哪一个类型的异常)

#ZeroDivisionError('division by zero'):异常对象

#traceback object:异常更详细的信息

sys.exc_info()可以直接定位最终引发异常的原因,结果也比较简洁,但是缺点是难以直接确定引发异常的代码位置。
假设有如下函数定义:

>def A():1/0

>def B():A()

>def C():B()

>C()        #直接调用C函数会抛出异常
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    C()
  File "<pyshell#23>", line 2, in C
    B()
  File "<pyshell#20>", line 2, in B
    A()
  File "<pyshell#17>", line 2, in A
    1/0
ZeroDivisionError: division by zero

使用sys.exc_info()查看异常信息

>try:
    C()
except:
    r=sys.exc_info()
    print(r)

    
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x000002B49138B280>)

#什么错误,这个类型的错误是什么情况,发生错误的位置

如果需要的话,可以使用traceback模块来查看详细信息:

>import traceback
>import sys
>def A():1/0

>def B():
    A()    
>def C():
    B()   
>try:
    C()
except:

#序列解包

#类型:excType;值:excValue;traceback对象:excTraceback
    excType,excValue,excTraceback=sys.exc_info()

#使用traceback模块里面的print_exception:查看excType,excValue,excTraceback这三个对象的信息;limit:回溯几级,limit=3,回溯三级
    traceback.print_exception(excType,excValue,excTraceback,limit=3)

#输出异常对象:excValue
    print(excValue)

#用traceback模块里的print_tb()查看excTraceback里面的信息
    traceback.print_tb(excTraceback)

#traceback.print_exception输出,看到底发生了什么错误

Traceback (most recent call last):
  File "<pyshell#18>", line 2, in <module>
  File "<pyshell#9>", line 2, in C
  File "<pyshell#6>", line 2, in B        #把limit改成4会有不一样
ZeroDivisionError: division by zero


division by zero        # print(excValue)输出(异常对象)

# traceback.print_tb(excTraceback)
  File "<pyshell#18>", line 2, in <module>
  File "<pyshell#9>", line 2, in C
  File "<pyshell#6>", line 2, in B
  File "<pyshell#3>", line 1, in A        #大概知道真正的错误在哪

8.6使用IDLE调试代码

  • 首先单击菜单“Debug”→”Debugger”打开调试器窗口
  • 然后打开并运行要调试的程序
  • 切换到调试器窗口进行调试

8.7使用pdb模块调试程序

pdb是Python自带的交互式源代码调试模块,代码文件为pdb.py,但需要导入后才能使用其中的功能,使用该模块可以完成代码调试的绝大部分功能,包括设置/清除(条件)断点、启用/禁用断点、单步执行、查看栈帧、查看变量值、查看当前执行位置、列出源代码、执行任意Python代码或表达式等等。

pdb还支持事后调试,可在程序控制下被调用。可以通过bdb和cmd接口对该调试器进行扩展。

pdb常用调试命令

pdb模块用法主要有三种:

  • 在交互模式下调试语句块、表达式、函数等多种脚本。
  • 在程序中嵌入调试功能。
  • 使用命令行调试程序。
(1)交模式调试:

pdb.run(statement[,globals[, locals]]):调试指定语句,可选参数globals和locals用来指定代码执行的环境,默认是__main __ 模块的字典。

pdb.runeval(expression[,globals[, locals]]):返回表达式的值,其他与run函数一样。

pdb.runcall(function[, argument, ... ]): 调试指定函数

pdb.post_mortem([traceback]):进入指定traceback对象的时候调试模式,如果没有指定traceback对象,则使用当前正在处理的一个异常。

>import pdb
>def f():
    x=5
    print(x)

    
>pdb.runcall(f)        #pdb.runcall:调试f函数
> <pyshell#4>(2)f()
(Pdb) n        #(Pdb):看到这个代表可以执行pdb的命令;n:执行下一个语句
> <pyshell#4>(3)f()
(Pdb) l        #l:查看代码
[EOF]
(Pdb) p x        #用p来查看下x的值
5
(Pdb) n        #next:执行下一条语句
5        # print(x)
--Return--
> <pyshell#4>(3)f()->None        #函数的返回值是空值
(Pdb) n        #函数结束,下面就没有了

(2)在程序中插入断点:

在程序中首先导入pdb模块,然后使用pdb.set_trace()在需要的位置设置断点。

在命令提示符环境下执行该程序或双击执行程序时将自动打开pdb调试环境,即使该程序当前不处于调试状态。

#使用pdb模块调试程序
import pdb
n=37
pdb.set_trace()     #pdb.set_trace():插入断点
for i in range(2,n):if n%i==0:print('No')break
else:print('Yes')
(3)以脚本模式进行调试

在命令行提示符下执行“python -m pdb 脚本文件名”,则直接进入调试环境;

当调试结束或程序正常结束以后,pdb将重启该程序;

参考


Python异常处理结构1:基础知识_哔哩哔哩_bilibili

Python异常处理结构2:常见异常处理结构_哔哩哔哩_bilibili

Python异常处理结构3:使用IDLE调试程序_哔哩哔哩_bilibili

Python异常处理结构4:使用pdb模块调试程序_哔哩哔哩_bilibili

这篇关于python程序设计基础:异常处理结构与程序调试、测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/746685

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测