跳转到内容

Python 编程/异常

来自维基教科书,开放的书籍,开放的世界


Python 2 使用异常处理所有错误。

异常 是一个信号,表示发生了错误或其他异常情况。有很多内置异常,它们指示诸如读取文件结尾或除以零之类的条件。您还可以定义自己的异常。

Python 中的异常一览

import random
try:
  ri = random.randint(0, 2)
  if ri == 0:
    infinity = 1/0
  elif ri == 1:
    raise ValueError("Message")
    #raise ValueError, "Message" # Deprecated
  elif ri == 2:
    raise ValueError # Without message
except ZeroDivisionError:
  pass
except ValueError as valerr:
# except ValueError, valerr: # Deprecated?
  print(valerr)
  raise # Raises the exception just caught
except: # Any other exception
  pass
finally: # Optional
  pass # Clean up

class CustomValueError(ValueError): pass # Custom exception
try:
  raise CustomValueError
  raise TypeError
except (ValueError, TypeError): # Value error catches custom, a derived class, as well
  pass                          # A tuple catches multiple exception classes

引发异常

[编辑 | 编辑源代码]

每当您的程序尝试进行错误或无意义的操作时,Python 都会对这种行为引发异常。

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

这个回溯 指示正在引发 ZeroDivisionError 异常。这是一个内置异常——请参阅下面的所有其他异常列表。

捕获异常

[编辑 | 编辑源代码]

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

如果您执行此代码

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

那么 Python 将打印此内容

您不能除以零!

如果您没有在 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 都没有 try/except 块来处理 ValueError。因此,引发的异常会传播到主代码,在那里有一个 异常处理块在等待它。此代码打印

该值无效。

有时找出确切的错误或自己打印 python 错误文本很有用。例如

try:
    the_file = open("the_parrot")
except IOError, (ErrorNumber, ErrorMessage):
    if ErrorNumber == 2: # file not found
        print("Sorry, 'the_parrot' has apparently joined the choir invisible.")
    else:
        print("Congratulation! you have managed to trip a #%d error" % ErrorNumber)
        print(ErrorMessage)

这将打印

抱歉,'the_parrot' 显然加入了无形的合唱团。

自定义异常

[编辑 | 编辑源代码]

类似于上面看到的代码可用于创建自定义异常并将信息与它们一起传递。这在尝试调试复杂项目时非常有用。以下是该代码的外观;首先创建自定义异常类

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, (instance):
    print("Caught: " + instance.parameter)

反复尝试

[编辑 | 编辑源代码]

使用 finally 恢复和继续

[编辑 | 编辑源代码]

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

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——实际上它是,但它是一种称为转义延续 的有限的 GOTO。延续是一种强大的函数式编程工具,学习它们很有用。

作为异常使编程更容易的简单示例,假设您想向列表中添加项目,但不想使用“if”语句来初始化列表,我们可以用此替换

if hasattr(self, 'items'):
    self.items.extend(new_items)
else:
    self.items = list(new_items)

使用异常,我们可以强调正常的程序流程——即我们通常只是扩展列表——而不是强调异常情况

try:
    self.items.extend(new_items)
except AttributeError:
    self.items = list(new_items)
[编辑 | 编辑源代码]
华夏公益教科书