文章目录
尽量用异常来表示特殊情况,而不要返回None
有时候我们编写函数时,会喜欢给None这个返回值特殊意义。这种做法在某些情况下是合理的,例如,计算两数相除的商,在除数为0的时候,计算结果是没有明确含义的(undefined),所以似乎应该返回None。
def divide(a, b):
try:
return a/b
except ZeroDivisionError:
return None
但是我们在拿到这个返回值做判断时,往往不会专门去判断函数的返回值是否为None,而是会假定:只要返回了与False等效的运算结果,就说明函数出错了。
x, y = 0, 5
result = divide(x, y)
if not result:
print("Invalid inputs") # This is wrong!
如果None这个返回值具备特殊意义,可能会使调用它的人写出错误的代码。有两种办法可以减少这个错误。
第一种办法,把返回值拆成两部分放到二元组(two-tuple)里。二元组的首个元素,表示操作是否成功,第二个元素,才是真正的运算结果。
def divide(a, b):
try:
return True, a/b
except ZeroDivisionError:
return False, None
这样做的问题在于,调用者可以用下划线为名称的变量,跳过元组的第一部分。这样写没错,但是却和返回None有着相似的错误。
第二种办法好一些,那就根本不返回None,把错误抛给上一级,让调用者必须处理它。
def divide(a, b):
try:
return a/b
except ZeroDivisionError as e:
raise ValueError("Invalid inputs") from e
这样写出来的代码,会比较清晰。
了解如何在闭包里使用外围作用域的变量
假如有一份列表,其中的元素全是数字,现在我们要对其排序,排序时要把出现在某个群组内的数字,放在群组外数字之前。
实现这个功能的常见用法是使用sort排序,把辅助函数传给key参数。
def sort_priority(values, group):
def helper(x):
if x in group:
return (0, x)
return (1, x)
values.sort(key=helper)
用这个函数应对一些简单的输入值。
numbers = [8, 3, 1, 2, 5, 4, 7, 6]
group = {
2, 3, 5, 7}
sort_priority(numbers, group)
print(numbers)
>>>
[2, 3, 5, 7, 1, 4, 6, 8]
这个函数能够运行的原因基于下列三个原因:
- Python支持闭包(closure):闭包是一种定义在某个作用域中的函数,函数引用了那个作用域中的变量。
- Python的函数是一级对象,我们可以直接引用函数、把函数赋给变量、把函数当成参数传给其它函数,并通过表达式及if语句对其进行比较和判断。
- Python使用特殊的规则来判断两个元组。它首先比较各元组中下标为0的元素,如果相等,再比较下标为1的元素,依次类推。
现在我们增加一个小需求,如果列表中出现了优先级更高的元素,我们希望sort_priority函数返回一个值,该函数的调用者,可以根据这个值作出相应地功能。
我们先试试下面这种简单的写法:
def sort_priority2(numbers, group):
found = False
def helper(x):
if x in group:
found = True
return (0, x)
return (1, x)
values.sort(key=helper)
return found
用刚才输入的值,来运行这个函数。
numbers = [8, 3, 1, 2, 5, 4, 7, 6]
group = {
2, 3, 5, 7}
found = sort_priority2(numbers, group)
print("Found:", found)
print