闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。
不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。
函数对象的作用域
和其他对象一样,函数对象也有其存活的范围,也就是函数对象的作用域。函数对象是使用def语句定义的,函数对象的作用域与def所在的层级相同。比如下面代码,我们在line_conf函数的隶属范围内定义的函数line,就只能在line_conf的隶属范围内调用。
代码如下:
def line_conf():
def line(x):
return 2*x+1
print(line(5)) # within the scope
line_conf()
print(line(5)) # out of the scope
line函数定义了一条直线(y = 2x + 1)。可以看到,在line_conf()中可以调用line函数,而在作用域之外调用line将会有下面的错误:
代码如下:
NameError: name 'line' is not defined
说明这时已经在作用域之外。
同样,如果使用lambda定义函数,那么函数对象的作用域与lambda所在的层级相同。
闭包
函数是一个对象,所以可以作为某个函数的返回结果。
代码如下:
def line_conf():
def line(x):
return 2*x+1
return line # return a function object
my_line = line_conf()
print(my_line(5))
上面的代码可以成功运行。line_conf的返回结果被赋给line对象。上面的代码将打印11。
如果line()的定义中引用了外部的变量,会发生什么呢?
代码如下:
def line_conf():
b = 15
def line(x):
return 2*x+b
return line # return a function object
b = 5
my_line = line_conf()
print(my_line(5))
新闻热点
疑难解答