Python 2 通过异常处理所有错误

异常是表示错误或其他异常情况的信号。Python 提供了许多内建的异常,表示诸如越界读取文件或除以零等错误情况。你也可以定义自己的异常。

概述

Python 中的异常使用概览:

import random
try:
  ri = random.randint(0, 2)
  if ri == 0:
    infinity = 1/0
  elif ri == 1:
    raise ValueError("Message")
    # raise ValueError, "Message" # 已弃用
  elif ri == 2:
    raise ValueError # 无消息
except ZeroDivisionError:
  pass
except ValueError as valerr:
  # except ValueError, valerr: # 已弃用?
  print(valerr)
  raise  # 抛出刚才捕获的异常
except:  # 其他任何异常
  pass
finally:  # 可选
  pass  # 清理工作

class CustomValueError(ValueError): pass  # 自定义异常
try:
  raise CustomValueError
  raise TypeError
except (ValueError, TypeError):  # ValueError 会捕获自定义异常,它是派生
  pass  # 一个元组可以捕获多个异常

抛出异常

每当程序尝试执行某个错误的或没有意义的操作时,Python 会抛出异常:

>>> 1 / 0
Traceback (most recent call last):
    File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero

这个 traceback 表明抛出了 ZeroDivisionError 异常。这是一个内建异常——下面会列出所有其他异常。

捕获异常

要处理错误,你可以在代码中设置异常处理块。tryexcept 关键字用于捕获异常。当 try 块中的错误发生时,Python 会查找匹配的 except 块来处理它。如果有匹配的块,执行会跳转到该块。

例如,执行以下代码:

try:
    print(1/0)
except ZeroDivisionError:
    print("You can't divide by zero!")

Python 将打印:

You can't divide by zero!

如果在 except 行没有指定异常型,它会捕获所有异常。通常在生产代码中这不是一个好主意,因为它意味着你的程序会忽略意外的错误以及 except 块本该处理的错误

异常可以传播到调用栈:

def f(x):
    return g(x) + 1

def g(x):
    if x < 0: raise ValueError("I can't cope with a negative number here.")
    else: return 5

try:
    print(f(-6))
except ValueError:
    print("That value was invalid.")

在此代码中,print 语句调用函数 f。该函数调用 g 函数,抛出 ValueError 异常。由于 fg 都没有处理 ValueErrortry/except 块,因此异常会传播到主代码中,在那里会有一个异常处理块等待它。此代码输出:

That value was invalid.

有时,查看具体的错误原因或打印 Python 错误文本本身会非常有用。例如:

try:
    the_file = open("the_parrot")
except IOError as (ErrorNumber, ErrorMessage):
    if ErrorNumber == 2:  # 文件未找到
        print("Sorry, 'the_parrot' has apparently joined the choir invisible.")
    else:
        print(f"Congratulation! you have managed to trip a #{ErrorNumber} error")
        print(ErrorMessage)

输出:

Sorry, 'the_parrot' has apparently joined the choir invisible.

自定义异常

上面看到的似代码可以用来创建自定义异常并传递信息。这在调试复杂项目时非常有用。以下是如何创建自定义异常的示例:

class CustomException(Exception):
    def __init__(self, value):
        self.parameter = value
    def __str__(self):
        return repr(self.parameter)

然后使用该异常:

try:
    raise CustomException("My Useful Error Message")
except CustomException as instance:
    print("Caught: " + instance.parameter)

重复尝试

异常可能会导致某个代码块在发生异常后不会被重新访问。在某些情况下,这可能会让程序使用的外部资源处于未知状态。

finally 子句允许程序员在发生异常时关闭这些资源。在 Python 2.4 到 2.5 版本之间,finally 子句的语法发生了变化。

Python 2.4:

try:
    result = None
    try:
        result = x / y
    except ZeroDivisionError:
        print("division by zero!")
    print("result is", result)
finally:
    print("executing finally clause")

Python 2.5:

try:
    result = x / y
except ZeroDivisionError:
    print("division by zero!")
else:
    print("result is", result)
finally:
    print("executing finally clause")

内建异常

Python 所有内建的异常可以在官方文档中找到。

异常的其他用法

异常不仅仅用于错误处理。如果你有一段复杂的代码,用来决定采取哪条路线,使用异常可以在做出决策后立即跳出代码。基于 Python 的邮件列表软件 Mailman 就是使用这种方式来决定如何处理邮件。将异常用于这种方式可能看起来像是某种 GOTO —— 事实上它确实是,但它是有限制的,称为逃逸续行。续行是一个强大的函数式编程工具,学习它可能会很有帮助。

例如,假设你想向一个列表添加项目,但你不想使用“if”语句来初始化列表,我们可以用异常来替代:

try:
    self.items.extend(new_items)
except AttributeError:
    self.items = list(new_items)

这样,我们就强调了程序的正常流程——通常我们只是扩展列表,而不是强调不寻常的情况。

Last modified: Friday, 31 January 2025, 12:44 AM