Python 错误和异常
一、基础概念
1.1 什么叫做语法错误?
ython 的语法错误或者称之为解析错,是初学者经常碰到的,如下实例
>>> while True print('Hello world')
File "<stdin>", line 1, in ?
while True print('Hello world')
^
SyntaxError: invalid syntax
这个例子中,函数 print() 被检查到有错误,是它前面缺少了一个冒号(:)。
语法分析器指出了出错的一行,并且在最先找到的错误的位置标记了一个小小的箭头。
1.2 什么叫做异常?
即便 Python 程序的语法是正确的,在运行它的时候,也有可能发生错误。运行期检测到的错误被称为异常。
1.3 try-except语法
try-except
结构是 Python 中用于异常处理的语法结构,它的一般形式如下:
pythonCopy codetry:
# 可能引发异常的代码块
# ...
except ExceptionType1 as variable1:
# 处理 ExceptionType1 类型的异常
# ...
except ExceptionType2 as variable2:
# 处理 ExceptionType2 类型的异常
# ...
# 可以有多个 except 块处理不同类型的异常
except (ExceptionType3, ExceptionType4) as variable34:
# 处理 ExceptionType3 或 ExceptionType4 类型的异常
# ...
else:
# 如果没有异常发生时执行的代码
# ...
finally:
# 无论是否发生异常,都会执行的代码
# ...
下面是 try-except
结构的主要部分解释:
try
块: 包含可能引发异常的代码块。当异常发生时,程序将跳转到适当的except
块处理异常。except
块: 用于捕获和处理特定类型的异常。每个except
块可以处理一个或多个异常类型,也可以使用括号将多个异常类型组合在一起。as variable
: 用于将捕获到的异常赋值给一个变量,以便在except
块中访问异常对象的信息。else
块: 包含在没有发生异常时执行的代码。它是可选的。finally
块: 包含无论是否发生异常都会执行的代码。它也是可选的。
二、异常关键词解析
2.1 raise 抛出异常
Python 使用 raise 语句抛出一个指定的异常。例如:
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: HiThere
raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。
如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出。
>>> try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise
An exception flew by!
Traceback (most recent call last):
File "<stdin>", line 2, in ?
NameError: HiThere
2.2 定义清理行为
try 语句还有另外一个可选的子句,它定义了无论在任何情况下都会执行的清理行为。 例如:
>>> try:
raise KeyboardInterrupt
finally:
print('Goodbye, world!')
Goodbye, world!
KeyboardInterrupt
以上例子不管 try 子句里面有没有发生异常,finally 子句都会执行。
如果一个异常在 try 子句里(或者在 except 和 else 子句里)被抛出,而又没有任何的 except 把它截住,那么这个异常会在 finally 子句执行后再次被抛出。
三、常用案例
3.1 基本用法
try:
# 可能引发异常的代码块
result = 10 / 0
except ZeroDivisionError:
# 捕获 ZeroDivisionError 异常
print("除零错误发生")
else:
# 如果没有发生异常时执行的代码
print("计算结果:", result)
finally:
# 无论是否发生异常,都会执行的代码
print("无论如何都会执行的代码")
这个案例演示了 try
、except
、else
和 finally
的基本用法。try
块中的代码引发了 ZeroDivisionError
异常,然后在 except
块中捕获了该异常。如果没有异常发生,将执行 else
块中的代码。无论如何,finally
块中的代码都会执行。
3.2 捕获多个异常
try:
# 可能引发多种异常的代码块
num = int("abc")
result = 10 / 0
except ValueError as ve:
# 捕获 ValueError 异常
print(f"ValueError: {ve}")
except ZeroDivisionError as zde:
# 捕获 ZeroDivisionError 异常
print(f"ZeroDivisionError: {zde}")
else:
print("计算结果:", result)
finally:
print("无论如何都会执行的代码")
这个案例展示了如何捕获多个异常。try
块中的代码引发了 ValueError
和 ZeroDivisionError
异常,分别在 except
块中捕获这两个异常。如果没有异常发生,将执行 else
块中的代码。
3.3 捕获所有异常
try:
# 可能引发任何异常的代码块
result = 10 / 0
except Exception as e:
# 捕获所有异常
print(f"发生异常: {e}")
else:
print("计算结果:", result)
finally:
print("无论如何都会执行的代码")
这个案例演示了如何捕获所有异常。try
块中的代码引发了 ZeroDivisionError
异常,而 except Exception as e
语句捕获了所有继承自 Exception
类的异常。无论是否有异常发生,都会执行 finally
块中的代码。
3.4 自定义异常
class CustomError(Exception):
"""自定义异常类"""
def __init__(self, message="发生自定义异常"):
self.message = message
super().__init__(self.message)
def perform_custom_operation(value):
"""执行可能引发自定义异常的操作"""
if value < 0:
raise CustomError("数值不能为负数")
return value * 2
# 使用自定义异常的案例
try:
user_input = int(input("请输入一个非负整数: "))
result = perform_custom_operation(user_input)
print("操作结果:", result)
except CustomError as ce:
print(f"捕获到自定义异常: {ce}")
except ValueError:
print("输入无效,请输入一个整数")
else:
print("操作成功完成")
finally:
print("无论如何都会执行的代码")
这个案例演示了如何创建和使用自定义异常。CustomError
是一个继承自 Exception
的自定义异常类,通过 perform_custom_operation
函数执行可能引发自定义异常的操作。在 try
块中,用户输入一个整数,然后调用 perform_custom_operation
函数。如果输入的值为负数,将引发自定义异常 CustomError
。在 except CustomError as ce
块中捕获到该异常,然后执行相应的处理逻辑。在 finally
块中,无论是否发生异常,都会执行相应的代码。
raise
是在 Python 中用于手动触发异常的关键字。它的作用是引发指定类型的异常,使得程序进入异常处理流程。
3.5 在循环中使用try-except
numbers = [1, 2, 3, 'four', 5]
for num in numbers:
try:
result = 10 / num
except ZeroDivisionError:
print("除零错误发生")
except Exception as e:
print(f"发生异常: {e}")
else:
print(f"计算结果: {result}")
finally:
print("无论如何都会执行的代码")
这个案例演示了如何在循环中使用 try-except
。对于列表中的每个元素,都会尝试执行除法操作,捕获可能发生的 ZeroDivisionError
或其他异常。无论是否有异常发生,都会执行 finally
块中的代码。
以上案例可以帮助你更好地理解 try-except
的不同用法和场景。