实例一

python

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

运行结果如下

python 逐行写入json超内存_python 逐行写入json超内存

Line函数是未定义的因为它是嵌套函数

我们再来看看javascript代码

python 逐行写入json超内存_环境变量_02

结果是一样的,甚至连错误信息都一样

下面我们再来

 

 

 

实例二

python 逐行写入json超内存_python_03

python 逐行写入json超内存_python_04

python 逐行写入json超内存_取值_05

结果也是一样的

实例三

如果line()的定义中引用了外部的变量,会发生什么呢?

python 逐行写入json超内存_python_06

python 逐行写入json超内存_取值_07

我们可以看到,line定义的隶属程序块中引用了高层级的变量b,但b信息存在于line的定义之外 (b的定义并不在line的隶属程序块中)。我们称b为line的环境变量。事实上,line作为line_conf的返回值时,line中已经包括b的取值(尽管b并不隶属于line)。

上面的代码将打印25,也就是说,line所参照的b值是函数对象定义时可供参考的b值,而不是使用时的b值。

而js的表现又是如何呢

python 逐行写入json超内存_取值_08

结果又是一样啊

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的__closure__属性中。比如下面的代码:

python 逐行写入json超内存_python_09

python 逐行写入json超内存_环境变量_10

__closure__里包含了一个元组(tuple)。这个元组中的每个元素是cell类型的对象。我们看到第一个cell包含的就是整数15,也就是我们创建闭包时的环境变量b的取值。

看看js 也有这个变量

python 逐行写入json超内存_环境变量_11

 

python 逐行写入json超内存_取值_12

 

 

实例四

python 逐行写入json超内存_python 逐行写入json超内存_13

python 逐行写入json超内存_python 逐行写入json超内存_14

这个例子中,函数line与环境变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用

python 逐行写入json超内存_环境变量_15

 

实例五

python 逐行写入json超内存_python_16

python 逐行写入json超内存_取值_17

这是因为在执行代码 c = foo()时,python会导入全部的闭包函数体bar()来分析其的局部变量,python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号"="的左面,被python认为是bar()中的局部变量。再接下来执行print c()时,程序运行至a = a + 1时,因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的值,结果找不到,就会报错

我们来看看js又是如何

python 逐行写入json超内存_python 逐行写入json超内存_18

python 逐行写入json超内存_环境变量_19

Js是没有保错的,但只要我们改一个东西就会立即报错

python 逐行写入json超内存_环境变量_20

我们在bar里面加一个var,声明a为局部变量

看看结果,我们加了个断点

python 逐行写入json超内存_取值_21

未执行的时候,a已经为undefined啦,那就可以说明a不是引入出面的a啦

我们我们来运行一下

python 逐行写入json超内存_取值_22

呵呵,a变成了nan啦,为什么呢

python 逐行写入json超内存_取值_23

原因是这个

这个时候就跟上面的python情况一模一样啦,而且现在没有构成闭包

 

实例六

python 逐行写入json超内存_环境变量_24

python 逐行写入json超内存_取值_25

跟我们预算的不一样啊,我们会以为2,3,4

我们来看看js

python 逐行写入json超内存_python_26

情况也一样

python 逐行写入json超内存_python_27

python 逐行写入json超内存_python 逐行写入json超内存_28

而这个形式并没有构成闭包,只是单纯的引用了全局变量而已

下一篇将分析原理篇,从python源码去解释函数是怎样运行的