Python基础语法——程序调试和异常处理

1.什么是异常

(1)程序运行过程中,总会遇到各种错误,有的错误是程序编写造成的,如本该输出字符串,结果却输出帧数,这种错误通常称之为bug,bug是必须修复的。

(2)有的错误是用户输入造成的,如让用户输入Emaile地址,结果却得到一个空字符串,这种错误可以通过检查用户输入来做出相应的处理

(3)还有一种错误是完全无法预测的,如写入文件是磁盘满了,或从网络抓取数据时网络突然中断,这种错误也称为异常,在程序中是必须要处理的,

(4)当Python解释器遇到一个无法预期的程序行为时,他就会输出一个异常,如果遇到初一0,或者打开一个不存在的文件等,当Python解释器遇到异常情况时,他会停止程序的运行。

2.常见错误和异常

(1)缺少冒号(:)

         在if,elif,for,while,class,def声明末尾需要添加":"

         错误提示:invalid syntax

(2)将赋值运算符=与比较运算符==混淆

         错误提示:invalid syntax

(3)代码结构的缩进问题

         错误提示:unindent does not match any oter indentation level

(4)修改元组和字符串是报错

     元组和字符串的值是不能修改的,如果修改他们的元素值,就会提示错误信息

       错误提示:‘tuple’ object does not support item assingnment

(5)连接字符串和非字符串

      如果将字符串与非字符串连接就会出现错误,可以是使用强制转换将非字符串转成字符串

      错误提示:can  only  concatenate str (not "int") to str

(6)在字符串收尾忘记加引号

       引号需成对出现

       错误提示:invalid character inidentifier

(7)变量或函数名拼写错误

        错误提示:name "ab" is not defined

 (8)引用超过列表的最大引用值

         错误提示:list index  out  ofrange

  (9)使用关键字作为变量名

         错误提示:invalid syntax

  (10)变量没有初始值时使用增值操作符(-=,+=等)

         错误提示:unsupported  opperand type(s) for -=:"str"and "int"

   (11)忘记给方法的第一个参数添加self参数

         myMethord() takes 0 positional arguments  but  1 was given.    

3.使用try....except语句处理异常

   (1)捕获异常 try...except...

看如下示例:


try:
    print('-----test--1---')
    open('123.txt','r')
    print('-----test--2---')
except IOError:
    pass

运行结果:

说明:

  • 此程序看不到任何错误,因为用except 捕获到了IOError异常,并添加了处理的方法
  • pass 表示实现了相应的实现,但什么也不做;如果把pass改为print语句,那么就会输出其他信息
  • 如果没有发生异常,就忽略except语句,try子句执行后结束。
  • 如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和except之后的名称相符,那么对应的except子句将被执行。
  • 如果一个异常没有与任何的except匹配,那么这个异常将会被传递到上层的try中。

小总结:

  • 把可能出现问题的代码,放在try中
  • 把处理异常的代码,放在except中

(2)except捕获多个异常

看如下示例:


try:
    print num
except IOError:
    print('产生错误了')

运行结果如下:

想一想:

上例程序,已经使用except来捕获异常了,为什么还会看到错误的信息提示?

答:

except捕获的错误类型是IOError,而此时程序产生的异常为 NameError ,所以except没有生效

修改后的代码为:


try:
    print num
except NameError:
    print('产生错误了')

运行结果如下:

实际开发中,捕获多个异常的方式,如下:

#coding=utf-8
try:
    print('-----test--1---')
    open('123.txt','r') # 如果123.txt文件不存在,那么会产生 IOError 异常
    print('-----test--2---')
    print(num)# 如果num变量没有定义,那么会产生 NameError 异常

except (IOError,NameError): 
    #如果想通过一次except捕获到多个异常可以用一个元组的方式

    # errorMsg里会保存捕获到的错误信息
    print(errorMsg)

 

注意:

  • 当捕获多个异常时,可以把要捕获的异常的名字,放到except 后,并使用元组的方式仅进行存储

(3)获取异常的信息描述

(4)捕获所有异常(except后的名称可以是空白的,表示except语句处理所有的异常。)

(5) else

咱们应该对else并不陌生,在if中,它的作用是当条件不满足时执行的实行;同样在try...except...中也是如此,即如果没有捕获到异常,那么就执行else中的事情


try:
    num = 100
    print num
except NameError as errorMsg:
    print('产生错误了:%s'%errorMsg)
else:
    print('没有捕获到异常,真高兴')

运行结果如下:

(6) try...finally...

             try...finally...语句用来表达这样的情况:

在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。 比如文件关闭,释放锁,把数据库连接返还给连接池等, try...finally...可以被当做清楚异常使用。不管try语句内是否运行失败,finally语句一定会被运行。try可以和except结合使用也可以和finally一起结合使用,但except和finally不能一起使用。

demo:


import time
try:
    f = file('test.txt')
    while True:
        content = f.readline()
        if len(content) == 0:
            break
        time.sleep(2)
        print(content)
finally:
    f.close()
    print('关闭文件')

说明:

test.txt文件中每一行数据打印,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些。在程序运行的时候,按Ctrl-c中断/取消程序。

我们可以观察到KeyboardInterrupt异常被触发,程序

4.异常类的实例

每当有一个异常类被输出时,该异常就会创建一个实例,此实例继承了异常类的所有属性。每一个异常类实例都有一个args属性。args 属性是一个元组格式,这个元组格式可能是只包含错误信息的字符串,也可能包含两个以上的元素。异常类的不同,这个元组格式也不同。

说明:

在except语句的右上方上加上一个inst变量,它是一个异常类实例。当IndexError异常发生时,inst实例就会被创建。inst实例的args属性是一个元组,输出该院组的第一个字符串就是IndexError异常的错误信息字符串“list index out of range”.

5.异常的传递

  

    def test1():
        print("----test1-1----")
        print(num)
        print("----test1-2----")


    def test2():
        print("----test2-1----")
        test1()
        print("----test2-2----")


    def test3():
        try:
            print("----test3-1----")
            test1()
            print("----test3-2----")
        except Exception as result:
            print("捕获到了异常,信息是:%s"%result)

        print("----test3-2----")



    test3()
    print("------华丽的分割线-----")
    test2()

运行结果:

 

总结:

  •   如果一个异常是在一个函数中产生的,例如函数A---->函数B---->函数C,而异常是在函数C中产生的,那么如果函数C中没有对这个异常进行处理,那么这个异常会传递到函数B中,如果函数B有异常处理那么就会按照函数B的处理方式进行执行;如果函数B也没有异常处理,那么这个异常会继续传递,以此类推。。。如果所有的函数都没有处理,那么此时就会进行异常的默认处理,即通常见到的那样
  • 注意观察上图中,当调用test3函数时,在test1函数内部产生了异常,此异常被传递到test3函数中完成了异常处理,而当异常处理完后,并没有返回到函数test1中进行执行,而是在函数test3中继续执行

6.抛出异常

(1)raise语句

Python使用raise语句抛出一个指定的异常,这个异常必须是一个异常的实例或异常的类。如果用户真相判断是否会跑除以二异常,而不想去处理它,那么使用raise是最佳的选择。

class ShortInputException(Exception):
    '''自定义的异常类'''
    def __init__(self, length, atleast):
        #super().__init__()
        self.length = length
        self.atleast = atleast
try:
    s = input('请输入 --> ')
    if len(s) < 3:
        # raise引发一个你定义的异常
        raise ShortInputException(len(s), 3)

except EOFError:
    print("你输入了一个结束标记EOF")
except ShortInputException as result:#x这个变量被绑定到了错误的实例
    print('ShortInputException: 输入的长度是 %d,长度至少应是 %d'% (result.length, result.atleast))
else:
    print('没有异常发生.')

运行结果如下:

注意

以上程序中,关于代码#super().__init__()的说明

这一行代码,可以调用也可以不调用,建议调用,因为__init__方法往往是用来对创建完的对象进行初始化工作,如果在子类中重写了父类的__init__方法,即意味着父类中的很多初始化工作没有做,这样就不保证程序的稳定了,所以在以后的开发中,如果重写了父类的__init__方法,最好是先调用父类的这个方法,然后再添加自己的功能

(2)结束解释器的运行

用户可以通过输出SystemExit异常强制结束Python解释器的运行。

使用sys.exit()函数会输出一个SystemExite异常,sys.exit()函数会结束线程。

(3)离开嵌套循环

在一个循环嵌套之内,break语句只能离开最内层的循环,而不能离开嵌套循环,此时就可以使用raise语句离开嵌套循环。

7.自定义异常

用户自定义异常与内置异常并无差别,只是内置异常是定义在exception模块中,当Python解释器启启动时,exception模块就会事先加载。自定义的异常类必须从任何一个Python的内置异常派生而来。

12程序调试

(1)使用assert语句

使用assert语句,可以帮助用户检测程序代码中的错误。

语法:assert <测试码>[,参数]

 测试码是一段返回T入耳或False的程序代码。若测试码返回true,侧继续执行后面的程序代码,若测试码返回false,assert语 句   就会输出一个AssertionError异常。并输出assert语句的[参数]作为错误信息字符串。

     

(2)使用__debug__语句

Python解释器有一个内置变量__debug__,__debug__在正常情况下的值是true,当以最佳模式启动,Python解释器时,__debug__值为false,用户不可以设置__debug__的值,,__debug__可以用来调试程序,下面的语法与assert语句的功能相同。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值