异常在程序里的作用
- Error Handling:能够在异常处理语句中捕获并响应错误信息
- Event Notification:即当我们应用程序在传入数据并进行数据处理过程中,针对不合法的事件我们是采取抛出异常而不是返回一个表示不合法的数据结果
- Special-case handling:在异常处理器处理程序个别极端情况,可以通过assert来检查条件是否如我们的预期值一样
- Termination actions:即保证程序中的资源能够在异常发生之后正常关闭
- Unusual control flows:不正常的控制流,使用raise抛出异常信息
异常处理的原理
在Python中,异常处理基于四个关键字:try, except, else, 和 finally。
try块:这部分代码是可能产生异常的代码。Python运行try块中的代码;如果出现异常,它会跳转到相应的except块。
except块:当try块中的代码触发异常时,程序执行流将转移到except块。可以指定多个except块来捕获不同类型的异常。
else块:如果try块没有引发异常,则执行else块中的代码。
finally块:无论是否发生异常,finally块中的代码总是会被执行。这对于执行一些清理工作是很有用的,如关闭文件或释放资源。
异常类型
异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行(通常是输入^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器(generator)发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除(或取模)零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入/输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块/对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引(index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误(对于Python 解释器不是致命的)
NameError 未声明/初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用(Weak reference)试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型(long)的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为(runtime behavior)的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告
异常处理的方法
捕获特定异常:可以通过指定具体的异常类型来捕获特定的异常。
def func():
return 1 / 0
try:
# 可能产生异常的代码
func()
except Exception as e:
# 处理异常
print(e)
# 捕获多个异常:可以在一个except子句中指定多个异常,使用元组来实现。
try:
# 可能产生异常的代码
func()
except (ZeroDivisionError, RuntimeError):
# 处理多种异常
# 捕获所有异常:使用 except Exception可以捕获所有的异常,但这通常不推荐,因为它会隐藏错误,不利于调试。
try:
# 可能产生异常的代码
func()
except Exception:
# 处理所有异常
print("error")
# 获取异常对象:可以通过as关键字来获取异常对象的引用。
try:
# 可能产生异常的代码
func()
except ZeroDivisionError as e:
# 使用异常对象e
print(e)
# 无异常时执行:使用else子句,在没有异常时执行代码。
try:
# 可能产生异常的代码
func()
except ZeroDivisionError:
# 处理异常
return False
else:
# 无异常时执行
print("exec end")
# 总是执行:使用finally子句来执行无论是否有异常都需要执行的代码。
try:
# 可能产生异常的代码
func()
except ZeroDivisionError as e:
# 处理异常
print(e)
finally:
# 总是执行的代码
print("exec end")
异常模块
当程序出现错误,python会自动引发异常,也可以通过raise显示地引发异常。一旦执行了raise语句,raise后面的语句将不能执行
raise Exception (, args [, traceback]])
def mye(level):
if level < 1:
raise Exception("Invalid level!") # 触发异常后,后面的代码就不会再执行
try:
mye(0) # 触发异常
except Exception as err:
print(1, err)
else:
print(2)
# 输出如下
# 1 Invalid level!
# 定义更详细的异常
class CustomError(Exception):
def __init__(self, message, level):
self.message = message
self.level = level
super().__init__(self.message)
def __str__(self):
return f"{self.message} (level: {self.level})"
# 函数触发自定义异常
def mye(level):
if level < 1:
raise CustomError("Invalid level", level) # 触发自定义异常
try:
mye(0) # 触发异常
except CustomError as err:
print(1, err)
else:
print(2)
# 输出结果:1 Invalid level (level: 0)
assert
assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常 断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况
def divide(a, b):
assert b != 0, "The divisor 'b' must not be zero"
return a / b
try:
result = divide(10, 0)
except AssertionError as e:
print(f"AssertionError: {e}")
# 检查函数返回值
def square(x):
return x * x
result = square(5)
assert result == 25, f"Expected 25, but got {result}"
Traceback
import sys
def func1():
raise NameError("--func1 exception--")
def main():
try:
func1()
except Exception as e:
exc_type, exc_value, exc_traceback_obj = sys.exc_info()
print("exc_type: %s" % exc_type)
print("exc_value: %s" % exc_value)
print("exc_traceback_obj: %s" % exc_traceback_obj)
if __name__ == '__main__':
main()
exc_type: <type 'exceptions.NameError'>
exc_value: --func1 exception--
exc_traceback_obj: <traceback object at 0x7faddf5d93b0>
sys.exc_info()获取了当前处理的exception的相关信息,并返回一个元组,元组的第一个数据是异常的类型(示例是NameError类型) ,第二个返回值是异常的value值,第三个就是traceback object
import sys
import traceback
def func1():
raise NameError("--func1 exception--")
def main():
try:
func1()
except Exception as e:
exc_type, exc_value, exc_traceback_obj = sys.exc_info()
traceback.print_tb(exc_traceback_obj)
if __name__ == '__main__':
main()
File "<ipython-input-23-52bdf2c9489c>", line 11, in main
func1()
File "<ipython-input-23-52bdf2c9489c>", line 6, in func1
raise NameError("--func1 exception--")
traceback.print_tb(tb[, limit[, file]])
- tb: 这个就是traceback object, 是我们通过sys.exc_info获取到的
- limit: 这个是限制stack trace层级的,如果不设或者为None,就会打印所有层级的stack trace
- file: 这个是设置打印的输出流的,可以为文件,也可以是stdout之类的file-like object。如果不设或为None,则输出到sys.stderr。
补充:更详细返回和精简调用方法+示例线程返回异常信息:https://www.cnblogs.com/Gaimo/p/14504732.html
实践建议
- 避免过度使用异常处理:不要使用异常处理来控制正常的程序流程。
- 精确地捕获异常:尽可能地捕获特定的异常,而不是使用一个宽泛的异常捕获。
- 清理资源:使用finally块来确保打开的资源被适当地清理。
- 记录异常信息:在处理异常时,记录详细的错误信息对于调试和日志记录是有帮助的。
评论区