第15条:了解如何在闭包里使用外围作用域中的变量
闭包在 python 中不是很好理解的内容,还是通过简单的例子逐步认识。
1.闭包
如果有一份列表,其中的元素都是数字,现在要对其排序,但排序时,要把出现在某个群组内的数字,放在群组外的那些数字之前。
def sort_priority(values, group):
def helper(x):
if x in group:
return (0, x)
return (1, x)
values.sort(key=helper)
numbers = [1, 5, 2, 7, 6, 4, 8, 3, 9]
group = {2, 3, 5, 7}
sort_priority(numbers, group)
print(numbers)
>>>
[2, 3, 5, 7, 1, 4, 6, 8, 9]
这里我们使用闭包实现了对列表的排序。之所以这里可以这样去实现,原因如下:
- Python支持闭包:闭包时一种定义在某个作用域中的函数,这种函数引用了那个作用域里面的变量。
这里 helper之所以能够访问 group 参数,是因为它是闭包。 - Python 的函数是一级对象,我们可以直接引用函数,把函数赋给变量或者当成参数传递给其他函数。
这里把 helper 函数,传给 sort 方法的 key 参数。 - Python 使用特殊的规则来比较两个元组(也可以比较两个列表)。首先比较各元组中下标为 0 的对应的元素,如果相等,再比较下标为 1 对应的元素,如果还是相等,就比较下标为 2 对应的元素,以此类推。
2.作用域
在表达式中引用变量时,Python 解释器按如下顺序遍历各作用域,
1)当前函数的作用域。
2)任何外围作用域。
3)包含当前代码的外围的作用域。
4)内置作用域。
如果这些地方都没有变量的定义,就会抛出 NameError 异常。
3.获取闭包内的数据
类似于在局部作用域获取全局变量,我们也可以在闭包中修改上一层作用域的变量。在 Python3 中,可以使用 nonlocal 关键字来完成。但是在 Python2 中没有这个关键字,只能使用闭包中使变量未定义的手段来实现到上一层作用域中查找该变量,这还是利用了 python 的作用域遍历顺序。
网友评论