【Python基础】异常处理机制什么是异常? 在编程中,异常是指在程序执行过程中发生的意外情况,这些情况会导致程序无法正
什么是异常?
在编程中,异常是指在程序执行过程中发生的意外情况,这些情况会导致程序无法正常运行。例如,当你试图除以零或访问不存在的文件时,就会引发异常。Python 提供了一套丰富的内置异常,用于处理各种错误情况。
Python 内置 的异常
- ZeroDivisionError:除以零。
- ImportError:导入模块或包失败。
- IndexError:访问列表、元组或其他序列类型的索引超出了范围。
- NameError:访问一个未定义的变量。
- SyntaxError:语法错误。
- TypeError:当传递给函数的参数类型不符合函数预期。
- ValueError:当传递给函数的参数值不符合预期,但类型正确时抛出。
- KeyError:当尝试从字典中获取一个不存在的键时抛出。
- OSError:操作系统相关的错误,如文件操作失败。
异常处理的基本结构
Python 的异常处理机制主要由 try
、except
、else
和 finally
关键字组成。这些关键字帮助程序在遇到错误时采取适当的行动,而不是让程序崩溃。
- try:块内包含可能引发异常的代码块,也就是你写的代码咯。
- except:捕获并处理特定类型的异常。可用多个
except
块来处理不同类型的异常。 - else:如果
try
块没有抛出任何异常,则执行这里的代码。 - finally:无论是否发生异常,都会执行这里的代码,通常用于清理工作。
示例
try:
num1 = 5
num2 = 2
result = num1 / num2
except ZeroDivisionError as e:
print(f"发生错误: {e}")
print("错误为:分母为0")
else:
print(f"结果是: {result}")
finally:
print("执行清理工作")
那你就要问了:既然明明知道会可能发生ZeroDivisionError异常,直接设置不能当分母为零不行?首先你的想法很棒!预防性检查比捕获异常更高效,因为异常处理涉及更多的开销。我们可以加一个逻辑先判断分母是否为零,如果为零则打印错误信息。这样可以避免
ZeroDivisionError
异常的发生。但是,如果分母可能在运行时发生变化,或者我们无法控制分母的值,那么使用try...except
结构来捕获异常会更加安全。即适用场景当输入是动态的或不可控时,或者当程序依赖于外部资源(如文件、网络连接等),而这些资源的状态可能在运行时发生变化。以及在多线程或多进程环境中,资源的状态可能在检查之后发生变化。上面这段话总结一句就是:你无法考虑到所有的情况。
你也可以通过将异常类型放在元组中来捕获多种异常。例如:
try:
# 可能引发异常的代码
pass
except (TypeError, ValueError) as e:
# 处理 TypeError 和 ValueError
print(f"捕获到异常: {e}") 但是缺点就是不知道到底是哪个异常
自定义异常
尽管 Python 提供了大量的内置异常类型,我们仍然需要创建自己的异常类型来更准确地描述特定的问题。自定义异常通过 继承Python内置异常类 Exception 来实现。例如,ValueError
和 TypeError
也都是 Exception
的子类。
1、创建自定义异常
只需要定义一个新的类并让它继承自 Exception
或者其他任何已存在的异常类即可。例如:
class MyCustomError(Exception):
"""这是一个自定义异常的示例"""
def __init__(self, message="这是一个自定义异常"):
self.message = message
super().__init__(self.message)
在这个例子中,MyCustomError
是一个自定义异常类,它有一个可选的消息参数。当这个异常被抛出时,如果提供了消息,那么这个消息就会被用来初始化异常对象。
关于__init__的补充(super涉及到OOP核心思想“继承”)
init 是Python中的构造函数,创建新对象时被自动调用(Javascript中的
new
关键字在 JavaScript 中的作用相当于 Python 中的class
关键字加上__init__
方法合而为一)。它接收一个参数 message,默认值是 "这是一个自定义异常"。这意味着如果你不提供任何消息,它会使用这个默认消息。(self 在JavaScript中即this 关键字来引用当前对象。)
super()
是一个内置函数,用于调用父类的方法。它返回一个代理对象,代表父类。通过这个代理对象,可以调用父类的方法。super().__init__(self.message)
的意思是:“调用Exception
类的__init__
方法,并把self.message
作为参数传递给它。” 这样做的目的是让Exception
类知道我们传递了一个错误消息。Exception
类的__init__
方法会处理这个消息,以便在异常被抛出时能显示它。
第一个 init 是 MyCustomError 类的 init 方法,初始化 MyCustomError 对象的属性。
第二个 init 是通过 super() 调用的 Exception 类的 init 方法,初始化 Exception 对象的属性。
为什么不能直接在
MyCustomError
的__init__
方法中处理消息?
直接在
MyCustomError
的__init__
方法中处理消息是可以的,但这样做会失去Exception
类提供的默认行为。通过调用Exception
类的__init__
方法,我们可以利用Exception
类已经定义好的逻辑,避免重复代码。具体来说:
- 利用现有逻辑:
Exception
类的__init__
方法已经定义了如何处理和存储错误消息。如果我们不调用它,就需要自己重新实现这些逻辑,这不仅增加了代码的复杂性,还可能导致错误。- 保持一致性:通过调用
Exception
类的__init__
方法,我们确保MyCustomError
异常在行为上与内置的异常一致,这使得代码更加一致和可预测。- 扩展性:如果
Exception
类在未来版本的 Python 中进行了改进,我们的MyCustomError
也能受益于这些改进,
2、抛出异常
使用 raise
关键字可以抛出异常。例如:
def check_value(x):
if x < 0:
raise MyCustomError("不能接受负数")
return x
这里,如果传入的值小于 0,函数 check_value
将会抛出 MyCustomError
异常。
转载自:https://juejin.cn/post/7422575000778489919