Python编程
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
异常。这是一个内建异常——下面会列出所有其他异常。
捕获异常
要处理错误,你可以在代码中设置异常处理块。try
和 except
关键字用于捕获异常。当 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
异常。由于 f
和 g
都没有处理 ValueError
的 try/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)
这样,我们就强调了程序的正常流程——通常我们只是扩展列表,而不是强调不寻常的情况。