异常
1 什么是异常
异常指程序运行过程中出现的非正常现象,例如用户输入错误、除数为零、需要处理的文件不存在、数组下标越界等。
python 中内建异常类的继承层次:
2 异常的解决顺序
1 )异常的顺序:发生异常》》异常定位》》处理异常。
2) 异常解决的态度:
- 不慌张, 细看信息, 定位错误。 看清楚报的错误信息, 并定位发生错误的地方。
- 百度并查看十个相关帖子。 将异常类信息进行百度, 至少查看十个以上的相关帖子。
- 以上两步仍然无法解决, 找老师和同学协助解决。
异常处理的结构
1 try…except 结构
try…except 是最常见的异常处理结构。 结构如下:
try 块包含着可能引发异常的代码, except 块则用来捕捉和处理发生的异常。 执行的时候, 如果 try 块中没有引发异常, 则跳过 ecept 块继续执行后续代码; 执行的时候, 如果 try块中发生了异常, 则跳过 try 块中的后续代码, 跳到相应的 except 块中处理异常; 异常处理完后, 继续执行后续代码。
例1:无异常时
try:
print("step1")
a = 3/2
print("step2")
except BaseException as e:
print("step3")
print(e)
print("step4")
执行结果:执行try里的语句,跳过 了ecept 块继续执行后续代码
step1
step2
step4
例2:有异常时
try:
print("step1")
a = 3/0
print("step2")
except BaseException as e:
print("step3")
print(e)
print("step4")
执行结果:跳过 try 块中的后续代码,也就是跳过了step2, 跳到相应的 except 块中处理异常
step1
step3
division by zero
step4
例3:循环输入数字, 如果不是数字则处理异常
while True:
try:
x = int(input("请输入一个数字:"))
print("您入的数字是",x)
if x == 88:
print("退出程序")
break
except:
print("异常:输入的不是一个数字")
执行结果:当你有异常时,跳出异常但程序还继续,直到达到停止的条件
您入的数字是 9
请输入一个数字:80
您入的数字是 80
请输入一个数字:g
异常:输入的不是一个数字
请输入一个数字:88
您入的数字是 88
退出程序
2 try…多个 except 结构
上面的结构可以捕获所有的异常, 工作中也很常见。 但是, 从经典理论考虑, 一般建议尽量捕获可能出现的多个异常( 按照先子类后父类的顺序,如果先写父类的话,执行的时候就不会执行子类) , 并且针对性的写出异常处理代码。 为了避免遗漏可能出现的异常, 可以在最后增加 BaseException。
结构如下:
先子类后父类的顺序
例:这里,程序不会自己停的
while True:
try:
a = input("请输入被除数:")
b = int(input("请输入除数: "))
c = float(a) / float(b)
print(c)
except ZeroDivisionError:
print("异常: 除数不能为 0")
except ValueError:
print("异常: 除数和被除数都应该为数值类型")
except NameError: #这个我不知道输入什么会报错,先留着??
print("异常: 变量不存在")
except BaseException as e:
print(e)
print(type(e))
执行结果:
请输入被除数:90
请输入除数: 3
30.0
请输入被除数:90
请输入除数: 0
异常: 除数不能为 0
请输入被除数:90
请输入除数: bb
异常: 除数和被除数都应该为数值类型
请输入被除数:
3 try…except…else 结构
try…except…else 结构增加了“ else 块” 。 如果 try 块中没有抛出异常, 则执行 else 块。 如果try 块中抛出异常, 则执行 except 块, 不执行 else 块。
例:这里,程序不会自己停的
while True:
try:
a = input("请输入被除数:")
b = int(input("请输入除数: "))
c = float(a) / float(b)
except BaseException as e:# 如果有异常输出异常,没异常打印值
print(e)
print(type(e))
else:
print(c)
执行结果:
请输入被除数:9
请输入除数: 0
float division by zero
<class 'ZeroDivisionError'>
请输入被除数:9
请输入除数: 3
3.0
请输入被除数:
4 try…except…finally 结构
try…except…finally 结构中, finally 块无论是否发生异常都会被执行; 通常用来释放 try 块中申请的资源。
finally 中的语句, 无论是否发生异常都执行.
例:
try:
f = open("d:/a.txt",'r')
content = f.readline()
print(content)
except:
print("文件未找到")
finally:
try:
f.close() #释放资源。 此处也可能会发生异常。 若发生异常, 则程序终止,不会继续往下执行
except BaseException as e:
print(e)
执行结果:
无异常时:D盘种,a.txt能打开。执行是看不出任何异常的。finally 中的语句, 无论是否发生异常都执行。
执行了finally语句
有异常,如D盘种,a.txt不存在。先执行except模块再进入finally模块。
文件未找到
执行了finally语句
name 'f' is not defined
5 return 语句和异常处理问题
由于 return 有两种作用: 结束方法运行、 返回值。 我们一般不把 return 放到异常处理结构中, 而是放到方法最后。
不要将 return 语句放到 try、 except、 else、finally 块中, 会发生一些意想不到的错误。 建议放到方法最后。(记住就行)
6 with 上下文管理
finally 块由于是否发生异常都会执行, 通常我们放释放资源的代码。 其实, 我们可以通过 with 上下文管理, 更方便的实现释放资源的操作。(感觉不是很get到,先记着)
结构:
with 上下文管理可以自动管理资源, 在 with 代码块执行完毕后自动还原进入该代码之前的现场或上下文。 不论何种原因跳出 with 块, 不论是否有异常, 总能保证资源正常释放。
with open("d:/a.txt","r") as f:
content = f. readline()
print (content)
print("程序执行结束! ")
执行结果:
12345678909876543212345678765432werthjhgfdsdfghj
程序执行结束!
7 trackback 模块
可以使用 Traceback 模块打印异常信息,或者使用 traceback 将异常信息写入日志文件。使用前要导入,import traceback。
使用 Traceback 模块打印异常信息:
import traceback
try:
print("step1")
num = 1/0
except:
traceback.print_exc()
执行结果:
Traceback (most recent call last):
step1
File "D:/PycharmProjects/MypythonTest/99chengfabiao/test_819.py", line 12, in <module>
num = 1/0
ZeroDivisionError: division by zero
使用 traceback 将异常信息写入日志文件:
import traceback
try:
print("step1")
num = 1/0
except:
with open("d:/a.log", "a") as f:
traceback.print_exc(file=f)
step1
打开 D盘的a.log。你就看到异常信息。
常见异常汇总
1 SyntaxError: 语法错误
int a = 3
int a =3
^
SyntaxError: invalid syntax
2 NameError: 尝试访问一个没有申明的变量
print(a)
print(a)
NameError: name 'a' is not defined
3 ZeroDivisionError: 除数为 0 错误(零除错误)
a = 3/0
a = 3/0
ZeroDivisionError: division by zero
4 ValueError: 数值错误
float("gaoqi")
float("gaoqi")
ValueError: could not convert string to float: 'gaoqi'
5 TypeError: 类型错误
123+"abc"
123+"abc"
TypeError: unsupported operand type(s) for +: 'int' and 'str'
6 AttributeError: 访问对象的不存在的属性
a=100
a.sayhi()
a.sayhi()
AttributeError: 'int' object has no attribute 'sayhi'
7 IndexError: 索引越界异常
a = [4,5,6]
a[10]
a[10]
IndexError: list index out of range
8 KeyError: 字典的关键字不存在
a = {'name':"gaoqi",'age':18}
a['salary']
a['salary']
KeyError: 'salary'
9 其他(ArithmeticError等)的异常
异常名称 | 说明 |
---|---|
ArithmeticError | 所有数值计算错误的基类 |
AssertionError | 断言语句失败 |
AttributeError | 对象没有这个属性 |
BaseException | 所有异常的基类 |
DeprecationWarning | 关于被弃用的特征的警告 |
EnvironmentError | 操作系统错误的基类 |
EOFError | 没有内建输入,到达 EOF 标记 |
Exception | 常规错误的基类 |
FloatingPointError | 浮点计算错误 |
FutureWarning | 关于构造将来语义会有改变的警告 |
GeneratorExit | 生成器(generator)发生异常来通知退出 |
ImportError | 导入模块/对象失败 |
IndentationError | 缩进错误 |
IndexError | 序列中没有此索引(index) |
IOError | 输入/输出操作失败 |
KeyboardInterrupt | 用户中断执行(通常是输入^C) |
KeyError | 映射中没有这个键 |
LookupError | 无效数据查询的基类 |
MemoryError | 内存溢出错误(对于 Python 解释器不是致命的) |
NameError | 4未声明/初始化对象 (没有属性) |
NotImplementedError | 尚未实现的方法 |
OSError | 操作系统错误 |
OverflowError | 数值运算超出最大限制 |
OverflowWarning | 旧的关于自动提升为长整型(long)的警告 |
PendingDeprecationWarning | 关于特性将会被废弃的警告 |
ReferenceError | 弱引用(Weak reference)试图访问已经垃圾回收了的对象 |
RuntimeError | 一般的运行时错误 |
RuntimeWarning | 可疑的运行时行为(runtime behavior)的警告 |
StandardError | 所有的内建标准异常的基类 |
StopIteration | 迭代器没有更多的值 |
SyntaxError | Python 语法错误 |
SyntaxWarning | 可疑的语法的警告 |
SystemError | 一般的解释器系统错误 |
SystemExit | 解释器请求退出 |
TabError | Tab 和空格混用 |
TypeError | 对类型无效的操作 |
UnboundLocalError | 访问未初始化的本地变量 |
UnicodeDecodeError Unicode | 解码时的错误 |
UnicodeEncodeError Unicode | 编码时错误 |
UnicodeError Unicode | 相关的错误 |
UnicodeTranslateError | Unicode 转换时错误 |
UserWarning | 用户代码生成的警告 |
ValueError | 传入无效的参数 |
Warning | 警告的基类 |
WindowsError | 系统调用失败 |
ZeroDivisionError | 除(或取模)零 (所有数据类型) |
自定义异常类
程序开发中, 有时候我们也需要自己定义异常类。 自定义异常类一般都是运行时异常, 通常继承 Exception 或其子类即可。 命名一般以 Error、 Exception 为后缀。
自定义异常由 raise 语句主动抛出
class AgeError(Exception): #继承 Exception
def __init__(self,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)#自定义异常由 raise 语句主动抛出
else:
print("正常的年龄:",age)
输入一个年龄:160
Traceback (most recent call last):
File "D:/PycharmProjects/MypythonTest/99chengfabiao/test_819.py", line 19, in <module>
raise AgeError(age)#自定义异常由 raise 语句主动抛出
__main__.AgeError: 160,年龄错误! 应该在 1-150 之间