Python 异常处理允许程序优雅地处理意外事件(例如无效输入或丢失文件)而不会崩溃。Python 不是突然终止,而是允许您检测问题、响应问题并在可能的情况下继续执行。

轮播-2.webp

让我们看一个例子以更好地理解它:

基本示例:处理简单异常

下面是一个基本示例,演示如何捕获异常并优雅地处理它:

n = 10

try:
    res = n / 0
except ZeroDivisionError:
    print("Can't be divided by zero!")


输出

Can't be divided by zero!

说明:将数字除以 0 会引发 ZeroDivisionError。try 块包含可能失败的代码,并且 except 块捕获错误,打印安全消息而不是停止程序。

错误和异常之间的区别

错误和异常都是程序中的问题,但它们的严重性和处理方式不同。让我们看看如何:

  • 错误:程序逻辑中存在无法处理的严重问题。示例包括语法错误或内存错误。
  • 异常:运行时发生的不太严重的问题,可以使用异常处理进行管理(例如,无效输入、丢失文件)。

示例:此示例显示了语法错误和运行时异常之间的区别。

# Syntax Error (Error)
print("Hello world"  # Missing closing parenthesis
# ZeroDivisionError (Exception)
n = 10
res = n / 0

说明:语法错误会完全停止代码运行,而像 ZeroDivisionError 这样的异常会在执行过程中发生,并且可以通过异常处理捕获。

语法和用法

Python 提供了四个主要关键字来处理异常:try、except、else,最后每个关键字都扮演着独特的角色。让我们看看语法:

try:
# 除 SomeException 之外的代码

# 代码
else:
# 代码
finally:
# 代码

  • try:运行可能导致错误的风险代码。
  • except:如果发生错误,则捕获并处理错误。
  • else:仅当 try 中没有发生异常时才执行。
  • final:无论发生什么情况,都会运行,这对关闭文件等清理任务有用。

示例:此代码尝试除法并使用 try-except-else-finally 正常处理错误。

try:

    n = 0
    res = 100 / n

except ZeroDivisionError:
    print("You can't divide by zero!")

except ValueError:
    print("Enter a valid number!")

else:
    print("Result is", res)

finally:
    print("Execution complete.")


输出

You can't divide by zero!
Execution complete.

解释:try 块尝试除法,除了块捕获特定错误,否则块仅在没有发生错误时执行,而 finally 块始终运行,表示执行结束。

请参阅 Python 内置异常 了解一些常见的异常。

Python 捕获异常

在 Python 中处理异常时,我们可以通过指定我们期望的异常类型来更有效地处理错误。这可以使代码更安全,也更易于调试。

1. 捕获特定异常

捕获特定异常会使代码以不同的方式响应不同的异常类型。它恰恰使您的代码更安全、更易于调试。它通过仅对您预期的确切问题做出反应来避免掩盖错误。

示例:此代码处理具有不同消息的 ValueError 和 ZeroDivisionError。

try:

    x = int("str")  # This will cause ValueError
    inv = 1 / x   # Inverse calculation

except ValueError:
    print("Not Valid!")

except ZeroDivisionError:
    print("Zero has no inverse!")


输出

Not Valid!

说明:发生 ValueError 是因为 “str” 无法转换为整数。如果转换成功但 x 为 0,则会捕获 ZeroDivisionError。

2. 捕获多个异常

如果我们需要以相同的方式处理多个异常,我们可以在单个块中捕获它们,或者如果不同类型的异常需要不同的处理,我们可以将它们分开。

示例:此代码尝试转换列表元素并处理 ValueError、TypeError 和 IndexError。

a = ["10", "twenty", 30] # Mixed list of integers and strings

try:
    total = int(a[0]) + int(a[1])  # 'twenty' cannot be converted to int

except (ValueError, TypeError) as e:
    print("Error", e)

except IndexError:
    print("Index out of range.")


输出

Error invalid literal for int() with base 10: 'twenty'

说明:尝试将“twenty”转换为整数时引发 ValueError。如果使用不兼容的类型,则可能会发生 TypeError,而如果列表索引超出范围,则会触发 IndexError。

3. 包罗万象的处理者及其风险

有时我们可能会使用包罗万象的处理程序来捕获任何异常,但它可以隐藏有用的调试信息。

示例:此代码尝试将字符串除以数字,这会导致 TypeError。

try:

    res = "100" / 20 # Risky operation: dividing string by number

except ArithmeticError:
    print("Arithmetic problem.")

except:
    print("Something went wrong!")


输出

Something went wrong!

说明:发生 TypeError 是因为您无法将字符串除以数字。裸露的 except 会捕获它,但这可能会使调试变得更加困难,因为实际的错误类型是隐藏的。仅将裸除用作最后的手段安全网。

引发异常

我们在 Python 中使用 raise 关键字引发异常, 后跟我们要触发的异常类的实例。我们可以从内置异常中进行选择,也可以通过继承 Python 的内置 Exception 类来定义我们自己的自定义异常。

基本语法:

raise ExceptionType(“错误消息”)

示例:如果给出了无效的年龄,则此代码会引发 ValueError。

def set(age):

    if age < 0:
        raise ValueError("Age cannot be negative.")
    print(f"Age set to {age}")
try:
    set(-5)
except ValueError as e:
    print(e)


输出

Age cannot be negative.

说明:该函数检查年龄是否无效。如果是,则引发 ValueError。这可以防止无效状态进入程序。

自定义异常

您还可以通过定义继承自 Python 内置 Exception 类的新类来创建自定义异常。这对于特定于应用程序的错误很有用。让我们看一个例子来了解如何作。

示例:此代码定义自定义 AgeError 并将其用于验证。

class AgeError(Exception):

    pass
def set(age):
    if age < 0:
        raise AgeError("Age cannot be negative.")
    print(f"Age set to {age}")
try:
    set(-5)
except AgeError as e:
    print(e)


输出

Age cannot be negative.

说明:这里,AgeError 是一种自定义异常类型。这使得错误消息在大型应用程序中更有意义。

优势

下面是使用异常处理的一些好处:

  • 提高可靠性:程序不会在意外输入时崩溃。
  • 关注点分离:错误处理代码与业务逻辑保持分离。
  • 更干净的代码:分散在代码中的条件检查更少。
  • 有用的调试:回溯准确显示问题发生的位置。

异常处理也有一些缺点,如下所列:

  • 性能开销:处理异常比简单的条件检查慢。
  • 增加复杂性:多种异常类型可能会使代码复杂化。
  • 安全风险:处理不善的异常可能会泄露敏感细节。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐