用返回值 None 表示特殊情况是很容易出错的,
因为这样的值在条件表达式里面,没办法与 0 和空白字符串之类的值区分,这些值都相当于 False 。
用异常表示特殊的情况,而不要返回 None。
让调用这个函数的程序根据文档里写的异常情况做出处理。
通过类型注解可以明确禁止函数返回 None,即便在特殊情况下,它也不能返回这个值。
示例
- 我们要编写一个辅函数计算两数相除的结果 。
- 在除数是 0 的情况下,返回 None 似乎相当合理,因为这种除法的结果是没有意义的。
```python
def careful_divide(a, b):
try:
except ZeroDivisionError:return a / b
return None
x, y = 1, 0 result = careful_divide(x, y) if result is None: print(‘Invalid inputs’) else: print(‘Result is %.1f’ % result)
- 不能判断被除数为 0
```python
def careful_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return None
x, y = 0, 5
result = careful_divide(x, y)
if not result:
print('Invalid inputs') # This runs! But shouldn't
-
方法一
元组的首个元素表示操作是否成功,第二个元素表示计算的实际值。
```python def careful_divide(a, b): try:return True, a / b
except ZeroDivisionError:
return False, None
x, y = 5, 0 success, result = careful_divide(x, y) if not success: print(‘Invalid inputs’)
<a name="KVaKD"></a>
# 方法二 - 抛出异常
- 不采用 None 表示特例,而是向调用方抛出异常 (Exception),让他自己去处理。
- 下面我们把执行除法时发生的 ZeroDivisionError 转化成 ValueError,告诉调用方输入的值不对
- (什么时候应该使用 Exception 类的子类,可参见第 87 条)。
```python
def careful_divide(a, b):
try:
return a / b
except ZeroDivisionError as e:
raise ValueError('Invalid inputs')
现在,调用方拿到函数的返回值之后,不用先判断操作是否成功了。
因为这次可以假设,只要能拿到返回值,就说明函数肯定顺利执行完了,所以只需要用 try 把函数包起来并在 else 块里处理运算结果就好(这种结构的详细用法,参见第 65 条)。
x, y = 5, 2
try:
result = careful_divide(x, y)
except ValueError:
print('Invalid inputs')
else:
print('Result is %.1f' % result)
使用类型注解
这个办法也可以扩展到那些使用类型注解的代码中(参见第 90 条),我们可以把函数的返回值指定为 float 类型,这样它就不可能返回 None 了。然而,Python 采用的是动态类型与静态类型相搭配的 gradual 类型系统,我们不能在函数的接口上指定函数可能抛出哪些异常(有的编程语言支持这样的受检异常(checked exception),调用方必须应对这些异常)。
所以,我们只好把有可能抛出的异常写在文档里面,并希望调用方能够根据这份文档适当地捕获相关的异常(参见第 84 条)。
下面我们给刚才那个函数加类型注解,并为它编写 docstring 。
def careful_divide(a: float, b: float) -> float:
"""Divides a by b.
Raises:
ValueError: When the inputs cannot be divided.
"""
try:
return a / b
except ZeroDivisionError as e:
raise ValueError('Invalid inputs')
总结
- 用返回值 None 表示特殊情况是很容易出错的,因为这样的值在条件表达式里面,没办法与 0 和空白字符串之类的值区分,这些值都相当于 False 。
- 用异常表示特殊的情况,而不要返回 None。让调用这个函数的程序根据文档里写的异常情况做出处理。
- 通过类型注解可以明确禁止函数返回 None,即便在特殊情况下,它也不能返回这个值。