python 异常处理和程序调试

一、常见的异常类型:

SyntaxErrorPython 不能理解程序

NameError:局部或全局变量名找不到

AttributeError:属性引用失败

IndexError:索引引用越界

TypeError:操作数的类型不正确

ValueError:操作数类型正确,但值非法

ZeroDivisionError:被零除

FileNotFoundError:文件未找到

IOErrorIO system 报告故障

二、异常处理

1try…except使用

try…except语句用于处理问题语句,捕获可能出现的异常。

try子句中的代码块放置可能出现异常的语句,except子句中的代码块处理异常。当异常出现时,Python会自动生成1个异常对象,该对象包括异常的具体信息,以及异常的种类和错误位置。

例题1:

编写函数getRatios(v1, v2)

假定参数v1v2是等长的数字列表,要求返回一个列表,该列表包含v1[i]/v2[i]有意义的值。

def getRatios(v1,v2):
    """
    Assumes v1 and v2 are lists  of equal length of numbers 
    ReturnsLa list containing  the meaningful values of
    v1[i]/v2[i]
    """
    ratios=[]
    for  index in range(len(v1)):
        try:
            ratios.append(v1[index]/(v2[index]))
        except ZeroDivisionError:
            ratios.append(float('NaN')) # NaN= Not a Number
        except:
            raise ValueError('getRatioscalled with bad arg')
    return ratios
    



try:
    print(getRatios([1.0,2.0,7.0,6.0],[1.0,2.0,0.,3.0,]))
    print(getRatios([],[]))
    print(getRatios([1.0,2.0],[3.0]))
except ValueError as msg:
    print(msg)

 输出结果:

[1.0, 1.0, nan, 2.0]
[]
getRatioscalled with bad arg

例题2:

使用try…except捕获FileNotFoundError异常

try:
    open('hello.txt','r')   #尝试打开一个不存在的文件
    print('读文件')
except FileNotFoundError:
    print('文件不存在')
except :
    print('程序异常')

 输出结果:

文件不存在

例题3:

捕获并处理除数为0ZeroDivisionError异常

def div(x,y):
    try:
        result=x/y
    except ZeroDivisionError: #捕获除数为0的异常
        print('0 不能做除数')
    else:  #若没有异常则执行以下代码
        print(result)




div(10,0)
div(10,5)

输出结果:

0 不能做除数
2.0

例题4:异常处理嵌套

#异常处理嵌套
def strtest(s):
    try:
        print(s[6])
        try: #嵌套异常
            print(s[0]+s[1])
            print(s[0]-s[1])
        except TypeError:
            print('字符串不支持减法运算')
    except:
        print('异常')

strtest('hello')
strtest('Hello world!') 

输出结果:

异常
w
He
字符串不支持减法运算

2try…finally的使用

try…except语句还可以添加1finally子句,无论异常是否发生,finally子句都会被执行。

finally子句通常用于关闭因异常而不能释放的系统资源。

例题5:用try......处理异常

try:
    number1,number2=eval(input('Enter two numbers,seperated by a comma:'))
    result=number1/number2
except ZeroDivisionError:
    print('Division by zero!')
except SyntaxError:
    print('A comma may be missing  in  the input')
except:
    print('Something wrong in the input')
else:
    print('No exceptions,the result is',result)
finally:
    print('executing the final clause')  

输出结果:

python 异常处理和程序调试_第1张图片

3、使用raise出异常

当程序中出现错误时,Python会自动引发异常。另外,在程序的任何地方都可以使用raise语句故意引发异常

一旦执行了raise语句,raise语句后的代码将不被执行。

raise语句通常用于抛出自定义异常,因为自定义异常并不在Python的控制范围之内,不会被Python自动抛出,应使用raise语句手工抛出。

例题6:使用raise抛出异常

#使用raise 抛出异常
def object(s):
    try:
        if s is None:
            print('s是空对象')
            raise NameError
        print(len(s))
    except NameError:
        print('空对象没有长度')
        
        
object(None)
object('abc')
object([1,2,3,4])
object([])
         

输出结果:

s是空对象
空对象没有长度
3
4
0

4、自定义异常

Python允许自定义异常,用于描述Python异常体系中没有涉及的异常情况。

自定义异常必须继承Exception类。

自定义异常按照命名规范以Error结尾,显式地表示该类是异常类。

自定义异常使用raise语句引发,且只能通过手工方式触发。

例题7:自定义异常

#自定义异常
class DivisionExceptionError(Exception):
    def __init__(self,x,y):
        Exception.__init__(self,x,y)
        self.x=x
        self.y=y
        
        
if __name__=='__main__':
    x=int(input('input a number:'))
    y=int(input('input another number:'))
    try:
        if x>0 and y>0:
            print(x/y)
        else:
            raise DivisionExceptionError(x,y) #抛出异常
    except DivisionExceptionError as div:
        print('arguments are error!')
        print('x=',div.x,'y',div.y)
        
    

输出结果:
python 异常处理和程序调试_第2张图片

5、断言

在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行时崩溃,不如在出现错误条件时就崩溃。

使用断言的目的是为了尽早识别bug且清楚它们是在何处出现的

在第一次碰到问题时就捕获它,使调试更容易,而不是之后再追踪

若用户提供了错误输入时应尽可能依靠抛出异常去处理,而断言常用于检查参数或值的类型。

assert语句用于检测某个条件表达式是否为真。

assert语句又称为断言语句,即assert认为检测的表达式永远为真。

if语句中的条件判断都可以使用assert语句检测。例如,检测某个元组中元素的个数是否大于1,如果assert语言断言失败,会引发AssertionError异常。

#assert语句使用
t=('hello',)
assert len(t)>=1
t=('hello')
assert len(t)==1
    

输出结果:

    assert len(t)==1

AssertionError

带异常参数的断言语句:

arguments]

功能:用来解释断言并更好的知道是哪里出了问题

lst=[1,2,3,4,5,6]
assert len(lst)>=5, '列表元素个数小于5'
lst=[1,2,3,4]
assert len(lst)>=5, '列表元素个数小于5'

输出结果:

 File "C:/Users/Administrator/.spyder-py3/temp.py", line 4, in
    assert len(lst)>=5, '列表元素个数小于5'

AssertionError: 列表元素个数小于5

6、多种异常的处理

可在except子句中指定多种异常来处理多种异常;

如果要分别处理不同的异常,可使用多个except子句;

如果在except子句中没有指定异常,它将捕获所有异常。

例题9:处理多种异常

#处理多种异常
def convert_to_int1(s,base): #指定多种异常
    try:
        return int(s,base)
    except (ValueError,TypeError):
        return 'error'
    
def convert_to_int2(s,base): #分别处理多种异常
    try:
        return int (s,base)
    except ValueError:
        return 'value error'
    except TypeError:
        return 'type error'
    
def convert_to_int3(s,base):
    try:
        return int(s,base)
    except:
        return 'error'
    
    
x1=convert_to_int1(8,10)
print(x1)
x1=convert_to_int1('abc',10)
print(x1)
x2=convert_to_int2(8,10)
print(x2)
x2=convert_to_int2('abc',10)
print(x2)
x3=convert_to_int3(8,10)
print(x3)
x3=convert_to_int3('abc',10)
print(x3)

输出结果:

error
error
type error
value error
error
error

三、调试

如果总能写出正确的代码,并在第一次测试时就能正确执行,当然很好。但实际编程过程中并不总是如此顺利。

如何测试代码是否正确,常用的方法有:

黑盒测试通过特定规范执行路径

白盒测试通过代码执行路径

将调试作为一个搜索过程使用二分查找的方法,分离并检查错误来源

1、测试和调试

在调试程序过程中我们需要一些方法:

测试方法使用不同的例子运行代码看其是否正确的方法

调试方法已经发现程序中有问题,如何修正程序的方法

  • 何时进行测试?何时进行调试?

    实际上,如果能弄清楚如何设计代码,那么测试和调试会更加简单。优秀的程序员会有这样的经验:

    将代码分解成独立的模块,从而独立地测试和调试;

    写出好的文档(写明输入、输出的期望是什么;即使代码没有执行对测试的限制,这种文档也是有价值的);

    记录可能的各种假设;

  • 测试之前要完成的工作:

    确保代码可以运行

    剔除语法错误

    剔除静态语义错误

    事实上,Python解释器可以自动处理上述两种错误

    准备一套预期结果(即对于一个特定的输入,期待会有怎样的输出)

2、测试套件

找到一系列输入,它们很有可能暴露错误,且不会花太多时间,但却十分有效,这就是所谓测试套件。

将输入分解为子集,为代码正确性提供等效信息;

构造测试套件,其中至少包含每个子集的一个元素;

运行测试套件。

测试方法:

随机测试:代码的正确率随测试次数的增加而增加;

黑盒测试:在测试时,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,测试者在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收和正确的输出

白盒测试:是通过程序的源代码进行测试而不使用用户界面。这种类型的测试需要从代码句法发现内部代码在算法,溢出,路径,条件等等中的缺点或者错误,进而加以修正。

 

 

 

你可能感兴趣的:(python)