允许使用异常, 但必须谨慎使用.
定义:
异常是一种跳出正常的控制流, 以处理错误或其它异常情况的方法.
优点:
处理正常情况的控制流不会和错误处理代码混在一起. 在特定情况下, 它也能让控制流跳出多层调用帧. 例如, 一步跳出N多层嵌套的函数, 而不必逐层传递错误代码.
缺点:
可能导致控制流晦涩难懂. 调用库函数时容易忘记处理异常.
结论:
使用异常时必须遵守特定要求:
优先使用合适的内置异常类. 比如, 用 ValueError
表示前置条件错误 (例如给必须为正数的参数传入了负值). 不要使用 assert
语句来验证公开API的参数值. 应该用 assert
来保证内部正确性, 不应该用 assert
来纠正参数或表示意外情况. 若要用异常来表示意外情况, 应该用 raise
. 例如:
正确:
def connect_to_next_port(self, minimum: int) -> int:
"""连接到下一个可用的端口.
参数:
minimum: 一个大于等于 1024 的端口号.
返回:
新的最小端口.
抛出:
ConnectionError: 没有可用的端口.
"""
if minimum < 1024:
# 注意这里抛出 ValueError 的情况没有在文档里说明,因为 API 的
# 错误用法应该是未定义行为.
raise ValueError(f'最小端口号至少为 1024,不能是 {minimum}.')
port = self._find_next_open_port(minimum)
if port is None:
raise ConnectionError(
f'未能通过 {minimum} 或更高的端口号连接到服务.')
assert port >= minimum, (
f'意外的端口号 {port}, 端口号不应小于 {minimum}.')
return port
错误:
def connect_to_next_port(self, minimum: int) -> int:
"""连接到下一个可用的端口.
参数:
minimum: 一个大于等于 1024 的端口号.
返回:
新的最小端口.
"""
assert minimum >= 1024, '最小端口号至少为 1024.'
port = self._find_next_open_port(minimum)
assert port is not None
return port
Error
为后缀, 并且不应该有重复 (例如 foo.FooError
).3.永远不要使用 except:
语句来捕获所有异常, 也不要捕获 Exception
或者 StandardError
, 除非你想:
如果你使用这种写法, Python 将非常宽容. except:
真的会捕获任何错误, 包括拼写错误的符号名、 sys.exit()
调用、 Ctrl+C
中断、单元测试错误和各种你不想捕获的错误.
4.最小化 try/except
代码块中的代码量. try
的范围越大, 就越容易把你没想到的那些能抛出异常的代码囊括在内. 这样的话, try/except
代码块就掩盖了真正的错误.
5.用 finally
表示无论异常与否都应执行的代码. 这种写法常用于清理资源, 例如关闭文件.