异常处理
什么是异常?
首先要清楚, 什么是异常, 异常就是程序运行时发生错误的信号 (在程序出现错误时, 则会产生一个异常, 若程序没有处理它, 则会抛出该异常, 程序的运行也随之终止), 在 python 中, 错误触发的异常如下
异常是由错误触发的, 那么错误有哪些情况呢?
1. 语法错误:
- # 语法错误示范一
- else
- # 语法错误示范二
- def test:
- pass
- # 语法错误示范三
- class Cal
- pass
- # 语法错误示范四
- print(hello
1. 语法错误 (这种错误, 根本过不了 python 解释器的语法检测, 必须在程序执行前就改正)
View Code
2. 逻辑错误
- # res=1/0
- # l=[1,2]
- # l[10]
- # age=input('>>:')
- # age=int(age)
- # res=1/0
- # l=[]
- # l[10000]
- # dic={
- }
- # dic['name']
- # class Foo:
- # pass
- # Foo.x
2. 逻辑错误示范
View Code
异常的种类
在平时编码过程中, 常见的异常有以下这些:
AttributeError 试图访问一个对象没有的树形, 比如 foo.x, 但是 foo 没有属性 x
IOError 输入 / 输出异常; 基本上是无法打开文件
ImportError 无法引入模块或包; 基本上是路径问题或名称错误
IndentationError 语法错误 (的子类) ; 代码没有正确对齐
IndexError 下标索引超出序列边界, 比如当 x 只有三个元素, 却试图访问 x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C 被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python 代码非法, 代码不能编译 (个人认为这是语法错误, 写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量, 基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值, 即使值的类型是正确的
当然, 还有其他异常, 这里就不做过多演示. 出现异常, 我们肯定想到要处理, 不然程序就直接报错崩溃了. 其实我们一直在处理异常, 只是没有发现, 比如要判断你输入的内容是不是数字, 我们以前是这么判断的:
- age = input('请输入你的年龄:').strip()
- if age.isdigit():
- int(age) #这是主逻辑
- elif age.isspace():
- print('输入的是空格!')
- elif len(age) == 0 :
- print('没有输入内容')
- else:
- print('其他异常!')
>>> 请输入你的年龄: dasdasf
>>> 其他异常!
在这里 if 就是在处理异常, 但是, 如果我还有其他程序也要运行, 那就要写成这样了:
- age = input('请输入你的年龄:').strip()
- if age.isdigit():
- int(age) #这是主逻辑
- elif age.isspace():
- print('输入的是空格!')
- elif len(age) == 0 :
- print('没有输入内容')
- else:
- print('其他异常!')
- num = input('请输入你的编号:').strip()
- if num.isdigit():
- int(num) #这是主逻辑
- elif num.isspace():
- print('输入的是空格!')
- elif len(num) == 0 :
- print('没有输入内容')
- else:
- print('其他异常!')
- View Code
这时候, 你会发现, 程序写的很长, 可读性差, 如果有十个这样的输入, 那这个程序就没法看了, 这时候, python 提供了一种异常处理的方法 try...except...
part1 基本语法
try:
被执行的逻辑
except 异常名称:
如果 try 中的逻辑出现异常, 就执行这段逻辑
现在用这套方法来处理上面的异常, 看看效果怎么样:
- try:
- age = input('请输入你的年龄:').strip()
- int(age)
- num = input('请输入你的编号:').strip()
- int(num)
- except ValueError as e: #根据报错知道错误类型是 ValueError
- print(e)
>>> 请输入你的年龄: 23
>>> 请输入你的编号: dwqd
- >>>invalid literal for int() with base 10: 'dwqd'
- View Code
这样一看代码简洁了很多啊, 效果很完美
part2 异常只能用来处理指定的异常情况, 其他情况不会处理
我们可以试一下, 把错误类型改成别的, 看看会怎样:
- try:
- age = input('请输入你的年龄:').strip()
- int(age)
- num = input('请输入你的编号:').strip()
- int(num)
- except IndexError as e:
- print(e)
>>> 请输入你的年龄: ffq
- Traceback (most recent call last):
- File "C:/Users/pengfy/PycharmProjects/untitled / 错误与异常 / 错误与异常. py", line 26, in <module>
- int(age)
- ValueError: invalid literal for int() with base 10: 'ffq'
- View Code
看来错误类型还要对应才行.
part3 多分支
- try:
- age = input('请输入你的年龄:').strip()
- int(age)
- num = input('请输入你的编号:').strip()
- int(num)
- l=[]
- l[10000]
- dic={}
- dic['name']
- except ValueError as e:
- print(e)
- except IndexError as e:
- print(e)
- except KeyError as e:
- print(e)
- print('我继续执行')
>>> 请输入你的年龄: 12
>>> 请输入你的编号: 321
>>>list index out of range
>>> 我继续执行
View Code
多加几个 except, 就可以处理不同分支的异常了, 这个和 if...else... 里面的 elif 很类似吧, 现在就有疑问了, 有没有像 if...else... 里面 else 这样的万能处理呢, 答案是肯定的.
part4 万能异常
为了避免写太多异常类型, 或者一些不清楚的错误类型不知道怎么写, 那么可以用 Exception:
- try:
- age = input('请输入你的年龄:').strip()
- int(age)
- num = input('请输入你的编号:').strip()
- int(num)
- dic={}
- dic['name']
- l=[]
- l[10000]
- except Exception as e:
- print(e)
- print('我继续执行')
>>> 请输入你的年龄: 213
>>> 请输入你的编号: 23
>>>'name'
>>> 我继续执行
View Code
这时候, 有人就会觉得, 万能异常这么厉害, 我还要写什么其他异常的, 全部用这个不就好啦? 这个怎么说呢, 要分两点来看吧:
1. 如果你想要的效果是, 无论什么异常, 你都直接无视或者说用一种处理机制, 那么就直接用吧, 没问题,
2. 如果你要根据异常类型处理不同机制, 那还得用多分支的方式,
当然, 你可以结合多分支和万能异常一起使用啊, 这样多分支的健壮性会更好
part5 异常的其他结构
下面来看看异常处理的其他结构:
- try:
- age = input('请输入你的年龄:').strip()
- int(age)
- num = input('请输入你的编号:').strip()
- int(num)
- # l=[]
- # l[10000]
- #
- # dic={}
- # dic['name']
- except ValueError as e:
- print('566')
- except IndexError as e:
- print('435')
- except KeyError as e:
- print('755')
- # except Exception as e:
- # print(e)
- else:
- print('try 里面没有异常出现, 执行我')
- finally:
- print('不管有没有异常, 我都执行, 我一般是做清理工作')
- print('我继续执行')
>>> 请输入你的年龄: 12
>>> 请输入你的编号: 21
>>>try 里面没有异常出现, 执行我
>>> 不管有没有异常, 我都执行, 我一般是做清理工作
>>> 我继续执行
View Code
- try:
- age = input('请输入你的年龄:').strip()
- int(age)
- num = input('请输入你的编号:').strip()
- int(num)
- l=[]
- l[10000]
- dic={}
- dic['name']
- except ValueError as e:
- print('566')
- except IndexError as e:
- print('435')
- except KeyError as e:
- print('755')
- # except Exception as e:
- # print(e)
- else:
- print('try 里面没有异常出现, 执行我')
- finally:
- print('不管有没有异常, 我都执行, 我一般是做清理工作')
- print('我继续执行')
>>> 请输入你的年龄: 32
>>> 请输入你的编号: 13
>>>435
>>> 不管有没有异常, 我都执行, 我一般是做清理工作
>>> 我继续执行
View Code
看完两个例子, 可以知道这里面的 else 和 if...else... 里面的完全是两回事, 主要不要混淆. 当 try 没有异常时, else 里面的逻辑才会执行, 而 finally 不论在什么情况下都会执行, 一般用来做清理工作, 比如说你在 try 里面打开了一个问题, 然后中途出现异常了, 那么你的文件还在内存中, 这时候你可以在 finally 里面关闭文件.
part6 主动触发异常
我们学过主动触发异常用的是 raise, 下面看一下能不能捕获:
- try:
- raise TypeError('打印错误')
- except TypeError as e:
- print(e)
>>> 打印错误
View Code
part7 自定义异常
如果你想自定义一个异常, 也是可以的. 异常是什么, 就是一个类嘛, 那我们就定义一个异常类看看:
- class Pengfyexception():
- def __init__(self,msg):
- self.msg = msg #报错打印的内容
- try:
- raise Pengfyexception('自定义的异常')
- except Pengfyexception as e:
- print(e)
- >>> Traceback (most recent call last):
- File "C:/Users/pengfy/PycharmProjects/untitled / 错误与异常 / 错误与异常. py", line 103, in <module>
- raise Pengfyexception('自定义的异常')
- TypeError: exceptions must derive from BaseException
- View Code
报错了, 看错误提示, 再看看 type 错误是怎么写的, 原来要继承一个叫 BaseException 的类, 再试一下:
- class Pengfyexception(BaseException):
- def __init__(self,msg):
- self.msg = msg #报错打印的内容
- try:
- raise Pengfyexception('自定义的异常')
- except Pengfyexception as e:
- print(e)
>>> 自定义的异常
View Code
完美了, 成了.
part8 断言
断言可以说就是 if 的一种简写, 直接看例子吧:
- def test():
- """一万行代码得到 ret"""
- ret = 1
- return ret
- res = test()
- assert res == 1
- """继续执行下面的代码"""
- View Code
如果判断不正确:
- def test():
- """一万行代码得到 ret"""
- ret = 1
- return ret
- res = test()
- assert res == 2
- """继续执行下面的代码"""
- >>>Traceback (most recent call last):
- File "C:/Users/pengfy/PycharmProjects/untitled / 错误与异常 / 错误与异常. py", line 122, in <module>
- assert res == 2
- AssertionError
- View Code
这个完全可以用 if 写:
- def test():
- """一万行代码得到 ret"""
- ret = 1
- return ret
- res = test()
- # assert res == 1
- if res != 1:
- raise AssertionError
- # """继续执行下面的代码"""
- View Code
效果完全一样
part9 try...except... 的好处和用法:
try...except... 就是取代了 if 的那种方法, 让你的代码在保证可读性的情况下, 还增强了健壮性, 提高了容错率, 使用这种方法:
1. 把错误处理和你的主逻辑分开了
2. 代码更容易组织, 更清晰, 复杂的任务更容易实现
3. 更安全了, 不会因为一些小错误导致程序崩溃
但是要清楚的一点是, if 和 try...except... 都是 python 中处理异常的方法, 不要学了 try 就说 if 和异常处理没有关系了. 其次, 学完这个后发现 try...except... 很强大, 是不是每一段代码都可以加这个处理异常, 就不用管报错了, 这是肯定不行的, try...except... 还是要慎重使用, 首先 try...except 是你附加给你的程序的一种异常处理的逻辑, 与你的主要的工作是没有关系的, 这种东西加的多了, 会导致你的代码可读性变差, 然后异常处理本就不是你混乱逻辑的保姆, 只有在错误发生的条件无法预知的情况下, 才应该加上 try...except
来源: https://www.cnblogs.com/pengfy/p/10649855.html