python语言第十天笔记

1399-温同学

发表文章数:72

热门标签

,
首页 » Python » 正文

1 异常机制简介

(1)异常的概念与处理简介

  所谓的异常,指的是程序运行过程中出现的非正常现象,用户输入不一定符合你的要求;你的程序要打开某个文件,这个文件可能不存在或者文件格式不对;你要读取数据库的数据,数据可能是空的;我们的程序在运行着,但是内存或硬盘可能满了等等。软件程序在运行过程中,非常可能遇到刚刚提到的这些问题,我们称之为异常,英文是:Exception,意思是例外。
  继所谓异常处理,就是指程序在出现问题时依然可以正确的执行剩余的程序,而不会因为异常而终止程序执行。
  继在没有异常机制的情况下,要拷贝一个文件,其伪代码为:

#将 d:/a.txt 拷贝到 e:盘
if "d:/a.txt"这个文件存在:
	if e 盘的空间大于 a.txt 文件长度:
		if 文件复制一半 IO 流断掉:
			停止 copy, 输出: IO 流出问题!
		else:
			copyFile("d:/a.txt","e:/a.txt")
	else:
		print("e 盘空间不够存放 a.txt! ")

  真正关键的是 copyFile(“d:/a.txt”,“e:/a.txt”) 这一句话,但是异常处理代码却写了一大堆,并且这么写对程序员的要求非常高,因为要考虑的东西很多。

  那么,我们如何解决应对异常情况呢? python 的异常机制给我们提供了方便的处理方式。如上情况,如果是用 python 的异常机制来处理,示意代码如下(仅限示意,不能运行):

#将 d:/a.txt 拷贝到 e:盘
try:
	copyFile("d:/a.txt","e:/a.txt")
except:								# 只要上面的出错,就执行下面的语句
	print("文件无法拷贝")

(2)异常类

  python中,一切都是类,所以引进了很多用来描述和处理异常的类,称为异常类。异常类定义中包含了该类异常的信息和对异常进行处理的方法。下面较为完整的展示了python 中内建异常类的继承层次:
python语言第十天笔记
BaseException类是所有异常的基类。

(3)异常格式

  如果运行 3/0,则在控制台打印:
python语言第十天笔记

  最后一句:Process finished with exit code 1,即“进程结束,退出码是1”。如果退出码是0,则表示正常退出,为1表示异常退出。

(3)异常定位

  当程序报错时,需要搞清楚错误在哪里,这就是异常处理最基本的技能——异常定位。

#coding=utf-8
#Traceback追溯,追根溯源。most recent call last最后一次调用。

def a():
    num = 1/0

def b():
    a()

def c():
    b()


c()

控制台输出

C:/python3.8.1/python.exe F:/拜师培训/3350_Python编程-pycharm版/第九节异常课件和源码/异常源代码/my01.py
Traceback (most recent call last):
  File "F:/异常源代码/my01.py", line 14, in <module>
    c()
  File "F:/异常源代码/my01.py", line 11, in c
    b()
  File "F:/异常源代码/my01.py", line 8, in b
    a()
  File "F:/异常源代码/my01.py", line 5, in a
    num = 1/0
ZeroDivisionError: division by zero

Process finished with exit code 1

控制台报了一堆错误,但实际上只有一个错误,其他都是由于连带产生的。根据Traceback一层层的地找,就能找到错误所在。

(4)解决异常的态度

解决每一个遇到的异常, 建议大家遵循如下三步:
  1.不慌张, 细看信息, 定位错误。 看清楚报的错误信息, 并定位发生错误的地方。
  2.百度并查看几个相关帖子。 将异常类信息进行百度,看一下别人是怎么解决的。
  3.以上两步仍然无法解决, 找老师和同学协助解决。

  正常情况, 自己遵循如上步骤解决 30 个以上的错误, 就能积累初步的调试经验, 以后遇到的大部分错误都能独立完成。

2 try…一个 except 结构

  try…except 是最常见的异常处理结构。 结构如下:

try:
	被监控的可能引发异常的语句块
except [BaseException [as e]]:
	异常处理语句块

  执行的时候, 如果 try 块中没有引发异常, 则跳过 except 块继续执行后续代码; 如果 try块中发生了异常, 则跳过 try 块中的后续代码, 跳到相应的 except 块中处理异常; 异常处理完后, 继续执行后续代码。
python语言第十天笔记
  上面的程序流程示意图中,try 块中的代码执行到第二行“a = 3/0”时遇到异常,try块的剩余代码不执行,也就是说,“print(“step2”)”是不执行的。
  except语句中的意思是:如果异常对象属于BaseException类,那么就把这个对象赋值给e。前面提到过,BaseException类是所有异常的基类,所以只要出现异常,必定属于BaseException类,那么e就能指向异常对象。
  我们执行下面的程序试试看:

#coding=utf-8
print("step0")
try:
    print("step1")
    a = 3/0
    print("step2")
except BaseException as e:
    print("step3")
    print(e)            # 打印异常对象的值,这里打印的是异常对象的描述
    print(type(e))      # 打印异常对象的属性

print("end!!!!")

输出

step0
step1
step3
division by zero
<class 'ZeroDivisionError'>
end!!!!

如果没发生异常,那么 except 块将不处理

#coding=utf-8
print("step0")
try:
    print("step1")
    a = 3/2
    print("step2")
except BaseException as e:
    print("step3")
    print(e)            # 打印异常对象的值
    print(type(e))      # 打印异常对象的属性

print("end!!!!")

输出

step0
step1
step2
end!!!!

  如果把BaseException改成NameError,则不会执行except语句

#coding=utf-8
print("step0")
try:
    print("step1")
    a = 3/0
    print("step2")
except NameError:
    print("step3")

print("end!!!!")

输出

p0
step1
Traceback (most recent call last):
  File "F:异常源代码/my02.py", line 5, in <module>
    a = 3/0
ZeroDivisionError: d

  只有错误类型为NameError时,才会执行except块
  例:输入一个数字,如果是88则打印“退出程序”,如果输入的是其他字符则抛出异常,直至输入成功

while True:
    try:
        x = int(input("请输入一个数字"))
        print("输入的数字:",x)
        if x==88:
            print("退出程序")
            break
    except BaseException as e:
        print(e)
        print("异常,输入的不是一个数字")


print("循环数字输入程序结束!")

执行的时候,先后输入5,a,88

请输入一个数字5
输入的数字: 5
请输入一个数字a
invalid literal for int() with base 10: 'a'
异常,输入的不是一个数字
请输入一个数字88
输入的数字: 88
退出程序
循环数字输入程序结束!

Process finished with exit code 0

3 try…多个 except 结构

  上面的结构可以捕获所有的异常, 但如果希望根据异常情况的不同,针对性地写出异常处理代码,那么需要用到多个except结构。

try:
	被监控的、 可能引发异常的语句块
except Exception1:
	处理 Exception1 的语句块
except Exception2:
	处理 Exception2 的语句块
...
except BaseException:
	处理可能遗漏的异常的语句块

  假如异常是Exception1,则执行处理Exception1的语句块,如果异常是Exception2,则执行处理Exception2的语句块;假如异常都不是前面列出来的,那就执行最后一个except语句块,这有点类似于选择结构中额 else 语句块,因为BaseException是所有异常类的基类。
  假如Exception1与Exception2有继承关系,那么应该把子类放在前面,父类放在后面,如果反着来,那么相当于只写了一个except语句块。

#coding=utf-8
#测试try...多个except结构

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)

输入

请输入一个被除数:0
请输入一个除数:0
异常。不能除以0

4 try…except…else 结构

  try…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)
print("程序结束!")

输入10和0

请输入一个被除数:10
请输入一个除数:0
float division by zero
程序结束!

输入10和5

请输入一个被除数:10
请输入一个除数:5
2.0
程序结束!

5 try…except…finally 结构

  try…except…finally 结构中, finally 块无论是否发生异常都会被执行; 通常用来释放 try 块中申请的资源。

try:
    a = input("请输入一个被除数:")
    b = input("请输入一个除数:")
    c = float(a)/float(b)
except BaseException as  e:
    print(e)
else:
    print(c)
finally:
    print("我是finally中的语句,无论发生异常与否,都执行!")
print("程序结束!")

  上面的程序片段中,else语句块可以省略,因为在try…except…finally 结构中,else语句块不是必须的。
  在读取文件的时候,如果在文件读取的过程中发生异常,使得程序中断,使得文件来不及关闭。这种情况适合使用try…except…finally 结构,将文件关闭的语句写到finally块中,如

try:
    f = open("d:/adddd.txt","r")
    content = f.readline()
    print(content)
except:
    print("文件未找到")
finally:
    print("run in finally。关闭资源")
    try:
        f.close()
    except BaseException as e:
        print(e)

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

输出

文件未找到
run in finally。关闭资源
name 'f' is not defined
程序执行结束!

  在上面的程序中,finally语句块里嵌套了一个try…except结构,若没有这个结构,当未找到相应的文件时,f 将为空。

try:
    f = open("d:/adddd.txt","r")
    content = f.readline()
    print(content)
except:
    print("文件未找到")
finally:
    print("run in finally。关闭资源")
    f.close()

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

输出

Traceback (most recent call last):
  File "F:/异常源代码/my07.py", line 12, in <module>
    f.close()
NameError: name 'f' is not defined

6 return语句与异常处理

  在函数ongoing,一般不要将 return 语句放到 try、 except、 else、finally 块中, 会发生一些意想不到的错误,建议放到方法最后。

7 常见异常的解决

(1)八个要掌握的异常
python语言第十天笔记
python语言第十天笔记
python语言第十天笔记
python语言第十天笔记
python语言第十天笔记
python语言第十天笔记

python语言第十天笔记
python语言第十天笔记

python语言第十天笔记
这八种异常要掌握怎么去调试。
(2)其他异常
其他异常要能借助网络来实现调试。

8 with 上下文管理

  finally 块由于是否发生异常都会执行, 通常我们放释放资源的代码。 其实,我们可以通过 with 上下文管理,更方便的实现释放资源的操作。
  with 上下文管理的语法结构如下:

with context_expr [ as var]:
	语句块

  with 上下文管理可以自动管理资源, 在 with 代码块执行完毕后自动还原进入该代码之前的现场或上下文。 不论何种原因跳出 with 块, 不论是否有异常, 总能保证资源正常释放。 极大的简化了工作, 在文件操作、 网络通信相关的场合非常常用。
  需要注意的是,with不是用来取代try…except…finally结构的,只是作为补充,方便我们再文件管理、网络通信时的开发。
  此外,with只保证释放资源,不保证异常处理,也就是说,如果在打开或读取资源的时候出现错误,那么同样会中断程序,只是它可以释放资源。

#coding=utf-8
#测试with上下文管理

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

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

输出

Traceback (most recent call last):
  File "F:/拜师培训/3350_Python编程-pycharm版/第九节异常课件和源码/异常源代码/my08.py", line 5, in <module>
    with open("d:/a.txt","r") as f:
FileNotFoundError: [Errno 2] No such file or directory: 'd:/a.txt'

Process finished with exit code 1

9 traceback 模块

  前面的异常处理机制,可以帮我们处理异常,但是控制台不会打印异常信息,如果我们要打印异常信息,需要导入traceback模块。

#coding=utf-8
#测试trackback模块的使用
import traceback

try:
    print("step1")
    num = 1/0
except:
    traceback.print_exc()	# 打印异常信息

输出

python语言第十天笔记
  注意,控制台打印的异常信息,并不是因为程序中断抛出的,而是调用相应的方法获得的,最后的退出码 exit code 是0,也就是说,程序正常结束。
  也可以通过 traceback.print_exc() 把异常信息写到指定文件中,如:

import traceback
try:
    print("step1")
    num = 1/0
except:
    with open("d:/a.txt","a") as f:
        traceback.print_exc(file=f)		# 异常信息写入日志文件

输出

step1

  把异常信息写入了D盘下的 a.txt 文件(如果这个文件不存在,则新建),打开如下:
python语言第十天笔记

10 自定义异常类

  程序开发中, 有时候我们也需要自己定义异常类。 自定义异常类一般都是运行时异常, 通常继承 Exception 或其子类即可。 命名一般以 Error、 Exception 为后缀。
自定义异常由 raise 语句主动抛出。

#coding=utf-8
#测试自定义异常类

class AgeError(Exception):  #继承Exception
    def __init__(self,errorInfo):   # errorInfo 用来描述错误信息
        Exception.__init__(self)
        self.errorInfo = errorInfo
    def __str__(self):              # 打印错误信息的时候会调用这个方法
        return str(self.errorInfo)+",年龄错误!应该在1-150之间"


############测试代码################
if __name__ == "__main__":   #如果为True,则模块是作为独立文件运行,可以执行测试代码
    age = int(input("输入一个年龄:"))
    if age<1 or age>150:
        raise AgeError(age)         # 抛出异常
    else:
        print("正常的年龄:",age)

输出
python语言第十天笔记

11 Pycharm调试模式

  步骤:1 设置断点 2 debug
重点:
(1)要知道帧区和变量区
(2)如何增加要观察的变量?
(3)五种常用的调试操作
python语言第十天笔记

未经允许不得转载:作者:1399-温同学, 转载或复制请以 超链接形式 并注明出处 拜师资源博客
原文地址:《python语言第十天笔记》 发布于2020-11-18

分享到:
赞(0) 打赏

评论 抢沙发

评论前必须登录!

  注册



长按图片转发给朋友

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

Vieu3.3主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录