Contents
30.3.2. 尽量抛异常,避免返回None¶
编写工具函数(utility function)时,许多Python程序员都爱用None这个返回值来表示特殊情况。对于某些函数来说,这或许有几分道理。
例如,我们要编写一个辅助函数计算两数相除的结果。在除数是0的情况下,返回None似乎相当合理,因为这种除法的结果是没有意义的。
def careful_divide(a, b):
try:
return a / b
except ZeroDivisionError:
return None
x, y = 1, 0
result = careful_divide(x, y)
if result is None:
print("Invalid inputs")
上面这种if语句,会把函数返回0时的情况,也当成函数返回None时那样来处理。这种写法经常出现在Python代码里,因此像careful_divide这样,用None来表示特殊状况的函数是很容易出错的。有两种办法可以减少这样的错误。
第一种办法是,利用二元组把计算结果分成两部分返回。
def careful_divide(a, b):
try:
return True, a / b
except ZeroDivisionError:
return False, None
x, y = 1, 0
success, result = careful_divide(x, y)
if not success:
print("Invalid inputs")
第二种办法比刚才那种更好,那就是不采用None表示特例,而是向调用方抛出异常(Exception),让他自己去处理。
def careful_divide(a, b):
try:
return a / b
except ZeroDivisionError:
raise ValueError("Invalid inputs")
x, y = 5, 2
try:
result = careful_divide(x, y)
except ValueError:
print("Invalid inputs")
else:
print(f"Result is {result:.1f}")
我们可以把有可能抛出的异常写在文档里面,并希望调用方能够根据这份文档适当地捕获相关的异常
def careful_divide(a, b):
"""
Args:
a:
b:
divide a/b
Returns:
ValueError: when the inputs cannot be divided.
"""
try:
return a / b
except ZeroDivisionError:
raise ValueError("Invalid inputs")
x, y = 5, 2
try:
result = careful_divide(x, y)
except ValueError:
print("Invalid inputs")
else:
print(f"Result is {result:.1f}")
要点:
用返回值None表示特殊情况是很容易出错的,因为这样的值在条件表达式里面,没办法与0和空白字符串之类的值区分,这些值都相当于False。
用异常表示特殊的情况,而不要返回None。
让调用这个函数的程序根据文档里写的异常情况做出处理。
通过类型注解可以明确禁止函数返回None,即便在特殊情况下,它也不能返回这个值。