异常机制的本质+异常的父子类关系+try多类型结构+常见异常汇总+traceback模块+自定义异常类+with上下文管理器+测试调试断点

一、异常

1、导引问题

在实际工作中,我们遇到的情况不可能是非常完美的,要解决Exception,我们要让程序做出合理的处理。

(1)异常机制的本质

异常指程序运行中出现的非正常现象,例如用户输入错误、除数为零、需要处理的文件不存在等等。

异常处理,是指程序出现问题时依然可以正确的执行剩余的程序,而不会因为异常而终止程序执行。

(2)异常的父子关系

碰到异常别害怕,反而应该高兴,解决的异常越多,我们会收获更多

I.首先先定位,在哪个文件里有问题;

II.追溯——Traceback 里面看到哪一行出现问题

III.最后会给一个原因,例如:ZeroDivisionError:division by zero

(3)解决异常问题的态度

I.不慌张,仔细看信息,定位错误,看清楚报的错误信息,定位发生错误的地方;

II.百度并查看解决方法,只需要复制错误描述这种关键信息;

III.以上两步都无法解决时,找老师和同学协助解决

2、try···一个 except 结构

try:

      被监控的可能引发异常的语句块——可以写很多句

except BaseException[as e]:

      异常处理语句块(如果有异常,要如何处理)

#try里面是监控语句,遇到异常就执行except部分,然后跳过继续执行下一步
print("step0")
try:
    print("step1")
    a = 3 / 0
    print("step2")
except BaseException as e:
    print("step3")
    print("发生异常")
    print(e)
    print(type(e))

print("end!!!!!!!!")

'''
step0
step1
step3
发生异常
division by zero——对异常进行了描述
<class 'ZeroDivisionError'>
end!!!!!!!!
'''
#示例:循环输入数字,如果不是数字则异常处理,直到输入88,则结束循环
'
#无限循环用while True
while True:
    a = input("请输入一个是数字:")
    print("您输入的数字为:", a)
    if int(a) == 88:   #条件语句不能赋值,但是控制语句可以赋值
        print("退出程序")
        break

print("程序结束")

这个程序里面,当我输入了一个字符串时,出现了报错的情况,这个时候就体现了异常处理的中重要性
    if int(a) == 88:   #条件语句不能赋值,但是控制语句可以赋值
这个代码有个问题是,如果输入的不是整数,就会报错
ValueError: invalid literal for int() with base 10: 'ni'



改进后的代码
while True:
    try:
        a = input("请输入一个是数字:")
        print("您输入的数字为:", a)
        if int(a) == 88:   #条件语句不能赋值,但是控制语句可以赋值
            print("退出程序")
            break
    except BaseException as e:
        print(e)

print("程序结束")
#输入了字母之后
#invalid literal for int() with base 10: 'ni'

3、try多个except结构

可以捕获所有的异常,但是要按照先子类后父类的顺序!

可以在最后增加BaseException,以免漏掉一些错误

#测试try···多个except结构

a = input("请输入一个被除数:")
b = input("请输入一个除数:")
c = float(a)/float(b)
print(c)
#ValueError: could not convert string to float: 'ee'
#可能会出现的错误有:输入的是字符串;输入的被除数为0


改进之后的代码如下:
try:
    a = input("请输入一个被除数:")
    b = input("请输入一个除数:")
    c = float(a) / float(b)
    print(c)

except ZeroDivisionError:
    print("异常,被除数不能为0")

except ValueError:
    print("异常,应输入数值")

except NameError:
    print("变量不存在")

except BaseException as e:
    print(e)

4、try···except···else结构

有异常的时候执行except,没有异常的时候执行else

执行完else以后再执行下一步

#try···except····else结构
try:
    a = input("请输入一个被除数:")
    b = input("请输入一个除数:")
    c = float(a) / float(b)
except BaseException as e:
    print(e)

else:
    print(c)

5、try···except···finally结构

Finally块无论是否发生异常都会被执行,通常用来释放try块中申请的资源

#try···except····finally结构
try:
    a = input("请输入一个被除数:")
    b = input("请输入一个除数:")
    c = float(a) / float(b)
except BaseException as e:
    print(e)

else:
    print(c)

finally:
    print("我是finally中的病句,无论是否发生异常,都要执行哦!")


请输入一个被除数:15
请输入一个除数:0
float division by zero
我是finally中的病句,无论是否发生异常,都要执行哦!
try:
    f = open("d:/dda.txt", "r")
    content = f.readline()
    print(content)

except:
    print("文件未找到")

finally:
    print("run in finally,关闭资源")
    f.close()

print("程序执行已结束")


代码执行的结果如下:
文件未找到
run in finally,关闭资源
 line 147, in <module>
    f.close()
NameError: name 'f' is not defined


*由于在finally里面没找到f文件,报错之后,不再执行最后一步“程序已结束”

6、常见异常汇总和说明

*关于return

#return语句有两种作用:

(1)结束方法运行;

(2)返回值

***我们一般不把return放在异常处理结构中,而是放在方法最后

#常见异常的解决

(1)SyntaxError:语法错误;

(2)NameError:尝试访问一个没有申明的变量;

(3)ZeroDivisionError:除数为0错误;

(4)ValueError:数值错误;

(5)TpyeError:类型错误;

(6)AttributeError:访问对象的不存在的属性;

(7)IndexError:索引越界异常;

(8)KeyError:字典的关键字不存在;

7、traceback模块的使用

用来追溯,打印异常信息

#测试Trackback模块的使用
import traceback

try:
    print("step1")
    num = 1/0
except:
    traceback.print_exc()


step1
Traceback (most recent call last):
  File "D:/developer_tools/python/pythonProject/异常处理.py", line 202, in <module>
    num = 1/0
ZeroDivisionError: division by zero
把错误信息详细得打印出来了!
import traceback

#a = "将异常信息输出到指定的文件里"
#b = a.center(50, "*")
以上两行代码不重要


try:
    print("step2")
    num = 1/0
except:
    with open("d:/a.txt","a") as f: #用a的话,每次的异常信息可以添加,用w会清空原有文档的内容
        traceback.print_exc(file=f) #括号里什么都不加的时候默认写在python中,当括号里写入文件地址的时候,就把异常写在文件里

8、自定义异常类

自定义异常一般都是运行时异常,通常继承Exception或其子类即可。明明一般以Error、Exception为后缀;

##测试自定义异常类
class AgeError(Exception):  #继承Exception类
    def __init__(self, errorInfo):  #通常需要重写一下构造器,固定的模式
        Exception.__init__(self)   #利用父类的初始函数
        self.errorInfo = errorInfo

    def __str__(self):
        return str(self.errorInfo) + "年龄错误!应该在1-150之间"
          #由于errorInfo 传入的是age,age又用int写为整数,说到底是个数字,所以将其格式转化为字符串,字符串进行相加,返回更全面的信息

在自定义异常类时,前面的代码都一样,主要就是self.errorInfo这里不同



a = "测试代码"
b = a.center(50, "#")
print(b)

if __name__ == "__main__":   #如果为True的话,则模块是作为独立文件运行的,可以测试代码
    age = int(input("输入一个年龄:"))

    if age < 1 or age > 150:
        raise AgeError(age)   #抛出异常的意思,这里的函数必须要传一个参数
    else:
        print("正常的年龄", age)

'''
输入一个年龄:200
Traceback (most recent call last):
  File "D:/developer_tools/python/pythonProject/异常处理.py", line 249, in <module>
    raise AgeError(age)
__main__.AgeError: 200年龄错误!应该在1-150之间
'''

二、with上下文管理器

finally块由于是否发生异常都会执行,通常我们用它来释放资源。另一种方法是通过with进行上下文管理,更方便的实现释放资源的操作

语法结构:

with context__expr[as var]:
       语句块

with上下文管理器可以自动管理资源,在with代码块执行完毕后自动还原进入该代码之前的现场或上下文。不论何种原因跳出with块,不论是否有异常,总能保证资源正常释放。极大简化了工作,在文件操作、网络通信相关的场合非常常用。

#测试with上下文管理,并不是用来取代try···except···finally结构的,是为了方便我们进行文件管理,网络通信时的开放

with open("d:/dda.txt", "r") as f:
    content = f.readline()
    print(content)

print("程序执行已结束")
#出现了报错的情况,是因为文件不存在

三、测试调试

1、断点

进行调试的核心是设置断点——程序运行到此处,暂时挂起,停止执行。我们可以详细在此观察程序的运行情况,方便做出进一步的判断。

(1)设置断点:

1>在行号后面单击即可增加断点;

2>在断点上再单击即可取消断点。

(2)通过debug来找bug,进入调试断点视图

(3)视图中的按钮含义如下:


<1>step over :若当前执行的是一个函数,则会把这个函数当成整体一步执行完,不会进入到这个函数内部;

<2>step into:若是当前执行的是一个函数,则会进入这个函数内部;

<3>step out :当单步执行到子函数内,用step out 就可以执行完子函数剩余下部分,并返回上一层函数

<4>run to cursor: 把光标作为一个断点,可以直接跳到光标所指向的地方

 

def aa():
    print("run in aa() start!")
    print("step1")
    num1 = 3
    num2 = num1 * 4
    nume3 = num2 * 5
    print("step2")
    print("run in aa() end!!!!!!")

if __name__  == "__main__":
    print("main:step1")
    aa()   *在这里设置断点
    print("main:step2")
    print("main:end!!!!!!")


'''
点击step over之后,会显示:
main:step1
run in aa() start!
step1
step2
run in aa() end!!!!!!
把aa()方法当做一个整体直接执行完
'''

在Debugger里面的Variables 下面有个加号是用来观察变量的,点击加号输入要观察的变量,可以看到没进行一步,变量的数值

 (1)step over 直接将方法aa()全部执行完

 

(2)step into 跳入到aa()方法里,点step into一下操作一步

(3)step out 将方法aa()剩下的步骤全部执行完,最好是在方法aa()里面再设置一个断点,这样就比较好看出来效果了

(4)run to cursor 运行到光标处,用的不太多

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值