异常介绍
1. 什么是异常
本节以Python为例:
异常Exception:代码写错了,解释器无法运行。只要包括书写上语法上的错误和运行时的错误。
错误从轻到重:拼写检查inspection < 普通information < 警告warning < 运行时错误runtime Error < 异常 Exception < 严重的错误Error < 崩溃
2. 错误栈
def foo():
print(1/0)
def boo():
print('hello')
foo()
boo()
错误跟踪栈 traceback:错误栈展示出错信息:哪一个文件、第几行、出错代码在哪个模块方法下、出错的代码。根据函数的镶嵌和执行顺序,按从早到晚排序。最后是出错类型和描述。
如何排错:看看错误栈的前面的信息,知道从哪个代码开始出错;看看后面的信息,知道哪一句代码出错了;看看最后一句错误类型和描述。
3. 遇到过的错误
- 变量未声明就调用。 如:
>>> b=1
>>>c=2
>>>print(a)
NameError: name 'a' is not defined
- 语法错误:少写冒号等。
>>>if a>b
... return a
SyntaxError: invalid syntax
- 缩进错误:
IndentationError: expected an indented block
- 索引错误:超出下标范围
>>>[1,2,3][3]
IndexError: list index out of range
- 类型错误:调用函数时参数的类型或个数不匹配。
>>>def foo():
... print(1/0)
...def boo():
... print('hello')
... foo()
...boo(1)
TypeError: boo() takes 0 positional arguments but 1 was given
- 值错误:
>>>int('h')
ValueError: invalid literal for int() with base 10: 'h'
- 零除错误:
>>>1/0
ZeroDivisionError: division by zero
- 递归错误:
RecursionError:maximum recursion depth exceeded
- 键错误:
>>>{'key':'value'}['aaa']
KeyError: 'aaa
异常捕获
场景:一个大型项目,业务逻辑复杂。当出现异常错误时,我们并不希望程序终止,希望程序主体功能运行;收集分析错误信息
try {
// 有可能抛出异常的代码
}
except (Exception e) {
// 异常处理
}
finally {
// 无论是否捕获到异常都会执行的程序
}
示例1 捕获异常
def foo():
try:
print(1/0)
except ZeroDivisionError:
print('不能除以0')
finally:
print('我最后执行')
print('world')
def boo():
print('hello')
foo()
print('world')
boo()
- 捕获异常: try…except…finally
- try 括住可能发生问题的语句。偷懒方法try括住程序最外层,但这样捕获后不好定位出错的地方。
- except :后面跟异常的类名,如果捕获到这种异常,那么就会执行语句块,执行发生异常后的一些处理,处理比如 用户提示信息、记录日志、业务逻辑。
- finally:不管程序正常运行,或是出现某种异常被捕获,在或是出现异常没有被捕获,最终都会执行
- 捕获异常应该适当使用,使用过多代码会乱,不用的话错误可能导致程序崩溃带来损失。 场景:捕获数据库操作代码。
示例2
# f = open('demo.txt')
try:
f = open('demo.txt')
content = f.read()
print(content) # try块里面的变量变成局部变量,注意外部不用引用内部局部变量
except FileNotFoundError:
print('文件未找到,请检查文件名')
except UnicodeDecodeError:
print('unicode解码错误')
except Exception as e: # e = FileNotFoundError()
print(e)
finally:
f.close()
-
try块里面的变量变成局部变量,注意外部不用引用内部局部变量
-
如果try块中的代码可能报多种异常,那么多写几个并列的except 语句。
-
不知道错误类的类名:可能会出现代码中定义错误之外的未知新错误.使用所有错误类的父类Exception 类来捕获。
-
finally 场景:打开文件资源,不管有没有出错,最终应该保证关闭文件。
-
as 把…作为… 。关键字:类似等号赋值,可以写成一行。
抛异常和自定义异常
代码中遇到问题有时主动抛出异常,交给上层函数处理。遇到新问题需要自定义异常。 错误可控,有点小问题就可以主动抛异常 终止程序运行。
class DivisionError(ValueError): # 自定义异常类
pass
def foo(num):
if num == 0:
# raise Exception
# raise ValueError('除数不能为0')
# raise ZeroDivisionError('除数不能为0')
raise DivisionError('除数不能为0')
print(10/num)
foo(1)
foo(2)
foo(0)
自定义异常信息,中文或跟项目相关信息。 raise ValueError(‘除数不能为0’)
可以自定义异常类,自定义类可以继承系统内置异常类。
抛异常好处:自定义 把问题集中处理