Python 异常处理!

嗨,你好啊,我是猿java

这篇文章,我们将通过适当的示例讨论如何使用try、except和finally语句来处理Python中的异常。

Python中的错误可以分为两种类型,即语法错误和异常。错误是由于程序中的问题而导致程序停止执行的情况。而异常是在出现某些内部事件时引发的,从而改变程序的正常流程。

Python中的异常类型

在 Python中,有几种内置的异常,当程序执行过程中出现错误时会抛出这些异常,以下是 Python中最常见的一些异常类型:

  • SyntaxError: 当解释器在代码中遇到语法错误时引发此异常,例如拼写错误的关键字、缺少的冒号或不平衡的括号。
  • TypeError: 当一个操作或函数应用于错误类型的对象时引发此异常,例如将字符串加到整数上。
  • NameError: 当变量或函数名称在当前作用域中未找到时引发此异常。
  • IndexError: 当列表、元组或其他序列类型的索引超出范围时引发此异常。
  • KeyError: 当在字典中找不到键时引发此异常。
  • ValueError: 当函数或方法调用时提供了无效的参数或输入时引发此异常,例如尝试将字符串转换为整数而该字符串不表示有效整数。
  • AttributeError: 当对象上找不到属性或方法时引发此异常,例如试图访问类实例的不存在的属性。
  • IOError: 当输入/输出操作失败时引发此异常,例如读取或写入文件时发生输入/输出错误。
  • ZeroDivisionError: 当尝试将数字除以零时引发此异常。
  • ImportError: 当导入语句未能找到或加载模块时引发此异常。

这些只是许多可能在Python中发生的异常类型中的一部分。通过使用try-except块或其他错误处理技术,适当地处理异常是很重要的,这样可以优雅地处理错误并防止程序崩溃。

语法错误和异常的区别

语法错误: 顾名思义,这种错误是由代码中的语法错误引起的,它会导致程序的终止。

以下示例代码中存在语法错误。‘if’语句应紧跟一个冒号(:),并且‘print’语句应缩进到‘if’块内部。

1
2
3
amount = 10000
if(amount > 2999)
print("amount > 2999")

异常: 异常是在程序语法正确的情况下引发的错误,但代码结果却发生错误。此错误不会停止程序的执行,但会改变程序的正常流程。

如下示例代码中,我们将‘marks’除以零,因此会发生称为‘ZeroDivisionError’的错误。‘ZeroDivisionError’ 发生在尝试将任何数字除以0时。

1
2
3
marks = 10000
a = marks / 0
print(a)

在上述示例中,由于我们试图将一个数字除以0,因此引发了ZeroDivisionError异常。

注意: Exception是Python中所有异常的基类。

  1. TypeError: 当一个操作或函数应用于错误类型的对象时引发此异常。

以下示例试图将两种不同数据类型相加,引发了‘TypeError’异常:

1
2
3
x = 5
y = "hello"
z = x + y

输出:

1
2
3
4
Traceback (most recent call last):
File "7edfa469-9a3c-4e4d-98f3-5544e60bff4e.py", line 4, in <module>
z = x + y
TypeError: unsupported operand type(s) for +: 'int' and 'str'

使用try-except块解决它:

代码尝试将一个整数(‘x’)和一个字符串(‘y’)相加,这是无效的操作,并会引发‘TypeError’异常。代码使用‘try’和‘except’块捕获此异常并打印错误消息。

1
2
3
4
5
6
x = 5
y = "hello"
try:
z = x + y
except TypeError:
print("错误: 不能将int和str相加")

输出:

1
错误: 不能将int和str相加

Try和Except语句——捕获异常

Try和except语句用于捕获和处理Python中的异常。可能引发异常的语句被放在try块中,而处理异常的语句则写在except块中。

示例:这里我们试图访问数组中越界的元素并处理对应的异常。

1
2
3
4
5
6
7
a = [1, 2, 3]
try:
print ("第二个元素 = %d" %(a[1]))
print ("第四个元素 = %d" %(a[3]))

except:
print ("发生错误")

输出:

1
2
第二个元素 = 2
发生错误

在上述示例中,可能导致错误的语句放在try语句中(我们的案例中是第二个print语句)。第二个打印语句尝试访问列表中的第四个元素,而该元素不存在,因而抛出异常。该异常被except语句捕获。

捕获特定异常

try语句可以有多个except条款,以指定不同异常的处理程序。请注意,最多只有一个处理程序会被执行。例如,我们可以在上述代码中添加IndexError。添加特定异常的一般语法是:

1
2
3
4
5
6
try:
# 语句
except IndexError:
# 语句
except ValueError:
# 语句

示例:捕获Python中的特定异常

代码定义了一个名为‘fun(a)’的函数,该函数根据输入a计算b。如果a小于4,它会尝试除以零,从而导致‘ZeroDivisionError’。代码在try-except块中调用fun(3)和fun(5)。它处理fun(3)时的ZeroDivisionError,并打印“ZeroDivisionError发生并已处理”。由于代码中没有‘NameError’异常,因此‘NameError’块不被执行。

1
2
3
4
5
6
7
8
9
10
11
12
def fun(a):
if a < 4:
b = a/(a-3)
print("b的值 = ", b)

try:
fun(3)
fun(5)
except ZeroDivisionError:
print("ZeroDivisionError发生并已处理")
except NameError:
print("NameError发生并已处理")

输出:

1
ZeroDivisionError发生并已处理

如果注释掉fun(3)行,输出将是:

1
NameError发生并已处理

上述输出是因为一旦 Python尝试访问 b的值,就会发生NameError异常。

带有 Else子句的Try语句

在Python中,你还可以在try-except块中使用else子句,该子句必须位于所有except块之后。代码仅在try块不抛出异常时才进入else块。

带有Else子句的Try语句

代码定义了一个名为AbyB(a, b)的函数,该函数计算c为((a+b) / (a-b))并处理潜在的ZeroDivisionError。如果没有发生除以零错误,它会打印结果。调用AbyB(2.0, 3.0)计算并打印-5.0,而调用AbyB(3.0, 3.0)尝试除以零,结果导致ZeroDivisionError,该异常被捕获并打印“a/b结果为0”。

1
2
3
4
5
6
7
8
9
10
def AbyB(a , b):
try:
c = ((a+b) / (a-b))
except ZeroDivisionError:
print ("a/b结果为0")
else:
print (c)

AbyB(2.0, 3.0)
AbyB(3.0, 3.0)

输出:

1
2
-5.0
a/b结果为0

Finally关键字在Python中的用法

Python提供了finally关键字,它始终在try和except块之后执行。无论是try块正常终止还是try块由于某些异常终止,最终块总是执行。最终块中的代码总是被执行。

语法:

1
2
3
4
5
6
7
8
9
try:
# 一些代码
except:
# 可选块
# 处理异常(如果需要)
else:
# 如果没有异常则执行
finally:
# 一些总是执行的代码

以下示例代码尝试执行除以零的整数除法,导致ZeroDivisionError。它捕获该异常并打印“不能除以零”。无论是否发生异常,最终块会执行并打印“这总是执行”。

1
2
3
4
5
6
7
try:
k = 5//0
print(k)
except ZeroDivisionError:
print("不能除以零")
finally:
print('这里总是执行')

输出:

1
2
不能除以零
这里总是执行

抛出异常

raise语句允许程序员强制发生特定异常。raise的唯一参数说明要引发的异常。这个参数必须是异常实例或异常类(从Exception派生的类)。

这段代码在try块中使用raise语句,带有消息“Hi there”主动引发一个NameError异常。然后,它捕获NameError异常,打印“发生异常”,并使用raise重新抛出相同的异常。这展示了如何在Python中引发和处理异常,允许自定义的错误消息和进一步的异常传播。

1
2
3
4
5
try: 
raise NameError("Hi there")
except NameError:
print ("发生异常")
raise

上述代码的输出将只会打印一行“发生异常”,但由于最后一行中的raise语句,最后也会发生运行时错误。所以在你的命令行上,输出将是:

1
2
3
4
Traceback (most recent call last):
File "/home/d6ec14ca595b97bff8d8034bbf212a9f.py", line 5, in <module>
raise NameError("Hi there") # Raise Error
NameError: Hi there

异常处理的优点:

  • 提高程序的可靠性: 通过正确处理异常,可以防止程序因意外错误或输入而崩溃或产生错误结果。
  • 简化错误处理: 异常处理允许将错误处理代码与主程序逻辑分离,使程序更易读和维护。
  • 代码更简洁: 使用异常处理,可以避免使用复杂的条件语句来检查错误,从而使代码更简洁、更易读。
  • 调试更容易: 当引发异常时,Python解释器会打印出异常发生的确切位置的追踪信息,使得调试代码更加容易。

异常处理的缺点:

  • 性能开销: 异常处理可能比使用条件语句检查错误要慢,因为解释器需要执行额外的工作来捕获和处理异常。
  • 增加代码复杂性: 异常处理可能使你的代码更复杂,特别是当你需要处理多种类型的异常或实现复杂的错误处理逻辑时。
  • 可能的安全风险: 处理不当的异常可能会暴露敏感信息或在代码中创建安全漏洞,因此务必要仔细处理异常,避免暴露过多有关程序的信息。

学习交流

如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。

drawing