用返回值 None 表示特殊情况是很容易出错的,
因为这样的值在条件表达式里面,没办法与 0 和空白字符串之类的值区分,这些值都相当于 False 。

用异常表示特殊的情况,而不要返回 None。
让调用这个函数的程序根据文档里写的异常情况做出处理。
通过类型注解可以明确禁止函数返回 None,即便在特殊情况下,它也不能返回这个值。

示例

  • 我们要编写一个辅函数计算两数相除的结果 。
  • 在除数是 0 的情况下,返回 None 似乎相当合理,因为这种除法的结果是没有意义的。 ```python def careful_divide(a, b): try:
    1. return a / b
    except ZeroDivisionError:
    1. return None

x, y = 1, 0 result = careful_divide(x, y) if result is None: print(‘Invalid inputs’) else: print(‘Result is %.1f’ % result)

  1. - 不能判断被除数为 0
  2. ```python
  3. def careful_divide(a, b):
  4. try:
  5. return a / b
  6. except ZeroDivisionError:
  7. return None
  8. x, y = 0, 5
  9. result = careful_divide(x, y)
  10. if not result:
  11. print('Invalid inputs') # This runs! But shouldn't
  • 为了避免这个问题,下面有两种解决方法。

    方法一

  • 元组的首个元素表示操作是否成功,第二个元素表示计算的实际值。
    ```python def careful_divide(a, b): try:

    1. return True, a / b

    except ZeroDivisionError:

    1. return False, None

x, y = 5, 0 success, result = careful_divide(x, y) if not success: print(‘Invalid inputs’)

  1. <a name="KVaKD"></a>
  2. # 方法二 - 抛出异常
  3. - 不采用 None 表示特例,而是向调用方抛出异常 (Exception),让他自己去处理。
  4. - 下面我们把执行除法时发生的 ZeroDivisionError 转化成 ValueError,告诉调用方输入的值不对
  5. - (什么时候应该使用 Exception 类的子类,可参见第 87 条)。
  6. ```python
  7. def careful_divide(a, b):
  8. try:
  9. return a / b
  10. except ZeroDivisionError as e:
  11. raise ValueError('Invalid inputs')

现在,调用方拿到函数的返回值之后,不用先判断操作是否成功了。
因为这次可以假设,只要能拿到返回值,就说明函数肯定顺利执行完了,所以只需要用 try 把函数包起来并在 else 块里处理运算结果就好(这种结构的详细用法,参见第 65 条)。

  1. x, y = 5, 2
  2. try:
  3. result = careful_divide(x, y)
  4. except ValueError:
  5. print('Invalid inputs')
  6. else:
  7. print('Result is %.1f' % result)

使用类型注解

这个办法也可以扩展到那些使用类型注解的代码中(参见第 90 条),我们可以把函数的返回值指定为 float 类型,这样它就不可能返回 None 了。然而,Python 采用的是动态类型与静态类型相搭配的 gradual 类型系统,我们不能在函数的接口上指定函数可能抛出哪些异常(有的编程语言支持这样的受检异常(checked exception),调用方必须应对这些异常)。
所以,我们只好把有可能抛出的异常写在文档里面,并希望调用方能够根据这份文档适当地捕获相关的异常(参见第 84 条)。

下面我们给刚才那个函数加类型注解,并为它编写 docstring 。

  1. def careful_divide(a: float, b: float) -> float:
  2. """Divides a by b.
  3. Raises:
  4. ValueError: When the inputs cannot be divided.
  5. """
  6. try:
  7. return a / b
  8. except ZeroDivisionError as e:
  9. raise ValueError('Invalid inputs')

总结

  • 用返回值 None 表示特殊情况是很容易出错的,因为这样的值在条件表达式里面,没办法与 0 和空白字符串之类的值区分,这些值都相当于 False 。
  • 用异常表示特殊的情况,而不要返回 None。让调用这个函数的程序根据文档里写的异常情况做出处理。
  • 通过类型注解可以明确禁止函数返回 None,即便在特殊情况下,它也不能返回这个值。