一、异常 程序运行时发生的错误主要是由于外部原因引起的, 例如非法输入或是其他操作失败等等. 这些因素并不在程序员的直接控制下, 而程序员只能预见一部分错误,编写常见的补救措施代码.类似 Python 这样支持引发和处理异常(这更重要)的语言, 可以让开发人员可以在错误发生时更直接地控制它们. 程序员不仅仅有了检测错误的能力, 还可以在它们发生时采取更可靠的补救措施. 由于有了运行时管理错误的能力, 应用程序的健壮性有了很大的提高。Python 采用了 try 块和 catching 块支持异常处理。 下面是python中一些常见的异常:
>>>#NameError: 尝试访问一个未申明的变量 >>> foo Traceback (innermost last): File "<stdin>", line 1, in ? NameError: name 'foo' is not defined >>># ZeroDivisionError: 除零异常 >>> 1/0 Traceback (innermost last): File "<stdin>", line 1, in ? ZeroDivisionError: integer division or modulo by zero >>> # SyntaxError: Python 语法错误 >>> for File "<string>", line 1 for ^ SyntaxError: invalid syntax 注:SyntaxError 异常是唯一不是在运行时发生的异常. 它代表 Python 代码中有一个不正确的结构, 在它改正之前程序无法执行. 这些错误一般都是在编译时发生, Python 解释器无法把你的脚本转化为 Python 字节代码. 当然这也可能是你导入一个有缺陷的模块的时候.有些异常不是由于错误条件引起的. 它们是 SystemExit 和KeyboardInterupt 。SystemExit 是由于当前 Python 应用程序需要退出, KeyboardInterupt 代表 用户按下了 CTRL-C (^C) , 想要关闭 Python,如果需要,可以捕获一些异常处理。 二、异常检测和处理 异常可以通过 try 语句来检测. 任何在 try 语句块里的代码都会被监测, 检查有无异常发生.try 语句有两种主要形式: try-except 和 try-finally . 可选的 else 子句处理没有探测到异常的时执行的代码. 而 try-finally 只允许检测异常并做一些必要的清除工作(无论发生错误与否), 没有任何异常处理设施. 1.try-except 语句 try-except 格式如下:
try: try_suite # watch for exceptions here 监控这里的异常 except Exception1 as e: except_suite # Exception1 处理代码 except Exception2 as e: except_suite # Exception2 异常2处理代码Example:
>>> try: ... f = open('blah', 'r') ... except IOError as e: ... print('could not open file:',e) ... could not open file: [Errno 2] No such file or directorytry 语句块中异常发生点后的剩余语句永远不会到达(所以也永远不会执行). 一旦一个异常被引发, 就必须决定控制流下一步到达的位置. 剩余代码将被忽略, 解释器将搜索处理器, 一旦找到,就开始执行处理器中的代码.如果没有找到合适的处理器, 那么异常就向上移交给调用者去处理, 这意味着堆栈框架立即回到之前的那个. 如果在上层调用者也没找到对应处理器, 该异常会继续被向上移交, 直到找到合适处理器. 如果到达最顶层仍然没有找到对应处理器, 那么就认为这个异常是未处理的, Python 解释器会显示出跟踪返回消息, 然后退出. 2.捕获所有异常 异常继承的树结构如下:
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StandardError | +-- BufferError | +-- ArithmeticError | | +-- FloatingPointError | | +-- OverflowError | | +-- ZeroDivisionError | +-- AssertionError | +-- AttributeError | +-- EnvironmentError | | +-- IOError | | +-- OSError | | +-- WindowsError (Windows) | | +-- VMSError (VMS) | +-- EOFError | +-- ImportError | +-- LookupError | | +-- IndexError | | +-- KeyError | +-- MemoryError | +-- NameError | | +-- UnboundLocalError | +-- ReferenceError | +-- RuntimeError | | +-- NotImplementedError | +-- SyntaxError | | +-- IndentationError | | +-- TabError | +-- SystemError | +-- TypeError | +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning所有异常都是从BaseException派生而来,因此我们可以通过如下语句捕获所有异常:
try: ... except BaseException as e: ...Python 提供给程序员的 try-except 语句是为了更好地跟踪潜在的错误并在代码里准备好处理异常的逻辑. 这样的机制在其他语言(例如 C ) 是很难实现的. 它的目的是减少程序出错的次数并在出错后仍能保证程序正常执行. 作为一种工具而言, 只有正确得当地使用它, 才能使其发挥作用.一个不正确的使用方法就是把它作为一个大绷带”绑定”到一大片代码上. 也就是说把一大段程序放入一个 try 块中, 再用一个通用的 except 语句 “过滤”掉任何致命的错误, 忽略它们.
# this is really bad code try: large_block_of_code # bandage of large piece of code except BaseException as e: pass # blind eye ignoring all errors很明显, 错误无法避免, try-except 的作用是提供一个可以提示错误或处理错误的机制, 而不是一个错误过滤器. 上边这样的结构会忽略许多错误, 避免把大片的代码装入 try-except 中然后使用 pass 忽略掉错误. 你可以捕获特定的异常并忽略它们, 或是捕获所有异常并采取特定的动作. 不要捕获所有异常,然后忽略掉它们. 3.else 语句 格式如下:
try: ... except: ... else: ...在 try 范围中没有异常被检测到时,执行 else 子句,如果出现异常则不会执行else语句。 4.finally 语句 finally 子句是无论异常是否发生,是否捕捉都会执行的一段代码.你可以将 finally 仅仅配合try 一起使用,也可以和 try-except(else 也是可选的)一起使用。 try-finally 语句 try-finally 语句常常用来维持一致的行为而无论异常是否发生.我们得知无论 try 中是否有异常触发,finally 代码段都会被执行
try: try_suite finally: finally_suite #无论如何都执行当在 try 范围中产生一个异常时,(这里)会立即跳转到 finally 语句段.当 finally 中的所有代码都执行完毕后,会继续向上一层引发异常。如果 finally 中的代码引发了另一个异常或由于 return,break,continue 语法而终止,原来的异常将丢失而且无法重新引发. try-except-else-finally 一个综合所有异常处理语法的异常处理格式如下:
try: try_suite except Exception1 as e: suite_for_Exception1 except Exception2 as e: suite_for_Exception2 finally: always_execute_suite