引言:
闭包在很多程序设计语言中都有出现,比如我们在网站开发时,经常使用的javascript中会接触过。在python中,闭包也是一个特别重要的概念。python中的装饰器本质上就是闭包。所以在我们介绍装饰器时,有必要理解闭包函数。
一.理解函数
1.函数定义
def 函数返回值 functionname([参数列表]):
函数体
以上就是一个函数定义的具体形式
2.函数原理
其实原先没有函数的概念。人们开始编写的都是顺序性程序,后来人们为了提高代码的重用性和可读性。便设计了函数的概念。以及变量等信息放入特定的堆栈中。然后进行操作,函数结束后将参数和变量等信息弹出堆栈的过程。
3.函数的局部参数和全局参数
在函数体内定义的参数为局部参数,定义在函数外的参数为全局参数。当定义的局部参数和全局参数重名时,按照变量的解析规则来进行。先从当前函数的作用域开始查找,如果没有发现,则再从上层的作用域查找。
```
#打印全局和局部变量的值
a="123"
def printa():
a="1234"
print(a)
print(a)
"""
当执行到printa函数内的print(a)时,从当前作用域内发现局部变量a="1234",
所以此时会打印出"1234",当函数执行完后,函数printa中的a的变量已经不存在了。最后程序打印123
"""
有些人又会问,那我如何在函数体内访问全局变量呢?我如何修改在函数体内修改全局变量呢?
访问可以直接访问,因为函数内找不到这个全局变量,就会到上一层作用域里找,最终一定会找到全局作用域里的全局变量。对全局变量进行修改等操作,需要在函数内使用global关键词即可。
#代码示例如下:
a="1234"
def revisea():
global a;
a="123"
print(a)
print(a)
#这时我们发现我们都是针对全局变量进行操作,会发现结果一样。
二.嵌套函数
Python允许创建嵌套函数(java不允许)。这意味着我们可以在函数里面定义函数而且现有的作用域和变量生存周期依旧适用。
#嵌套函数示例
def out():
a,b=2,3 #1
def process(a,b): #2
return a+b #3
return process(a,b) #4
print(out())
"""
当执行到#1时,我们发现定义了a,b两个变量,#2又定义了一个函数process,进
行函数体#3,发现只是对a,b进行求和。而a,b两个变量在在函数定义上的参数上存在,
所有外部函数out中也定义了a,b变量。但此时#3中a,b只是参数列表中的局部变量。
当执行到#4时,返回了process函数处理的返回值。
而此时传入process函数的a,b两变量是在out函数作用域里的,所有最后的处理结果为5
"""
你们也许看到过这样的行为:“python把频繁要用的操作变成函数作为参数进行使用,像通过传递一个函数给内置排序函数的key参数从而来自定义排序规则。
def out(a,b):
def inner():
return a+b
return inner
#返回函数,python中一切皆对象,函数是一个特殊的对象
myinner=out(1,2)
"""
针对这样一个嵌套函数来说,程序只提供了一个外部函数调用out,根本无法直接调用内部函数inner,
inner函数也会随之消失。所有我们在out函数返回时,直接返回inner函数名。并保存在一个变量myinner中,最后调用相应的函数即可。
"""
但是从变量的生存周期来看,该怎么理解呢?我们的变量a,b是函数out的一个本地变量,这意味着只有当函数out正在运行的时候才会存在。根据我们已知的python运行模式,我们没法在函数outer返回之后继续调用函数inner,在函数inner被调用的时候,变量a,b早已不复存在,可能会发生一个运行时错误。
万万没想到,返回的函数inner居然能够正常工作。Python支持一个叫做函数闭包的特性,用人话来讲就是,嵌套定义在非全局作用域里面的函数能够记住它在被定义的时候它所处的封闭命名空间。这能够通过查看函数的func_closure属性得出结论,这个属性里面包含封闭作用域里面的值(只会包含被捕捉到的值,比如x,如果在out里面还定义了其他的值,封闭作用域里面是不会有的)
三.闭包
1.定义:
函数闭包:嵌套定义在非全局作用域里面的函数能够记住它在被定义的时候它所处的封闭命名空间。(函数能够记住他所有的封闭的上下文环境),一个函数和它的环境变量合在一起,就构成了一个闭包(closure)
2.应用
网上看到一些关于python闭包使用的案例,不过个人觉得,多数的示例都不是很贴切。其实最广泛的应用场景就是装饰器.我将在下一个系列中讨论到装饰器。本文部分借鉴了文章http://python.jobbole.com/81683/,我也借此机会学习了。