翻译:《实用的Python编程》03_03_Error_checking

虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节。

程序是如何运行失败的

Python 不对函数参数类型或值进行检查或者校验。函数可以处理与函数内部语句兼容的任何数据。

def add(x, y): return x + y add(3, 4) # 7 add('Hello', 'World') # 'HelloWorld' add('3', '4') # '34'

如果函数中有错误,它们将(作为异常)在运行时出现。

def add(x, y): return x + y >>> add(3, '4') Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'str' >>>

为了验证代码,强烈建议进行测试(稍后介绍)。

异常

异常用于发出错误信号。

要自己触发异常,请使用 raise 语句:

if name not in authorized: raise RuntimeError(f'{name} not authorized')

要捕获异常,请使用 try-except 语句:

try: authenticate(username) except RuntimeError as e: print(e) 异常处理

异常传递到第一个匹配的 except :

def grok(): ... raise RuntimeError('Whoa!') # Exception raised here def spam(): grok() # Call that will raise exception def bar(): try: spam() except RuntimeError as e: # Exception caught here ... def foo(): try: bar() except RuntimeError as e: # Exception does NOT arrive here ... foo()

要处理异常,请将语句放到 except 块里面。 except 块里面可以添加要处理该错误的任何语句。

def grok(): ... raise RuntimeError('Whoa!') def bar(): try: grok() except RuntimeError as e: # Exception caught here statements # Use this statements statements ... bar()

异常处理之后,从 try-except 之后的第一个语句继续执行。

def grok(): ... raise RuntimeError('Whoa!') def bar(): try: grok() except RuntimeError as e: # Exception caught here statements statements ... statements # Resumes execution here statements # And continues here ... bar() 内置异常

有非常多的內建异常。通常,异常名称表明出了什么问题(例如,因为提供错误的值而触发 ValueError)。下述列表不是一份详尽的清单,请访问 文档 以获取更多信息。

ArithmeticError AssertionError EnvironmentError EOFError ImportError IndexError KeyboardInterrupt KeyError MemoryError NameError ReferenceError RuntimeError SyntaxError SystemError TypeError ValueError 异常值

异常具有一个关联值。它包含有关错误的更明确的信息。

raise RuntimeError('Invalid user name')

这个值是异常实例的一部分,它被放置在提供给 except 的变量中。

try: ... except RuntimeError as e: # `e` holds the exception raised ...

e 是异常类型的一个实例。但是,当打印的时候,它通常看起来像一个字符串。

except RuntimeError as e: print('Failed : Reason', e) 捕获多个异常

可以使用多个 except 块捕获不同类型的异常:

try: ... except LookupError as e: ... except RuntimeError as e: ... except IOError as e: ... except KeyboardInterrupt as e: ...

或者,如果处理不同异常的语句是相同的,则可以对它们进行分组:

try: ... except (IOError,LookupError,RuntimeError) as e: ... 捕获所有的异常

要捕获所有的异常,请使用 Exception 。如下所示:

try: ... except Exception: # DANGER. See below print('An error occurred')

通常,像这样编写代码是个坏主意,因为这说明不知道程序为什么会失败。

捕获异常的错误方式

这里是一个使用异常的错误方式。

try: go_do_something() except Exception: print('Computer says no')

这将捕获所有可能的错误,并且,当代码因为某些根本没想到的原因(如卸载 Python 模块等)运行失败时,可能无法进行调试。

更好的方式

如果想要捕获所有的错误,这有一个更明智的方法。

try: go_do_something() except Exception as e: print('Computer says no. Reason :', e)

它报告了失败的明确原因。当编写捕获所有可能异常的代码时,拥有查看/报告错误的机制几乎总是一个好主意。

不过,通常来说,最好在合理的范围内尽量窄地捕获异常。仅捕获能处理的异常。让其它错误通过——也许其它代码可以处理。

重新触发异常

使用 raise 传递捕获的错误。

try: go_do_something() except Exception as e: print('Computer says no. Reason :', e) raise

这允许你采取措施(例如:记录日志)并将错误传递给调用者。

异常的最佳实践

不要捕获异常,而是失败发生时“停止运行,发出预警”(Fail fast and loud)。如果重要的话,别人会处理的。只有你是那个人的时候才捕获异常。即,只捕获可以恢复并正常运行的错误。

finally 语句

finally 语句指定无论是否发生异常都必须运行的代码。

lock = Lock() ... lock.acquire() try: ... finally: lock.release() # this will ALWAYS be executed. With and without exception.

通常使用 finally 语句安全地管理资源(尤其是锁,文件等)。

with 语句

在现代代码中,try-finally 语句通常被 with 语句取代。

lock = Lock() with lock: # lock acquired ... # lock released

一个更熟悉的例子:

with open(filename) as f: # Use the file ... # File closed

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzpyx.html