内容简介:在正式讲「闭包」之前我们首先得先知道「嵌套函数」这么一个东西,我在之前的文章中(首先我们来看一个例子:上面就是一个简单的嵌套函数的例子,在上面的代码中,在函数
在正式讲「闭包」之前我们首先得先知道「嵌套函数」这么一个东西,我在之前的文章中( 零基础学习 Python 之函数对象 )说过,函数不单单可以作为对象来传递,还可以在一个函数里面嵌套一个函数,这个就是我们今天要讲的嵌套函数。
嵌套函数
首先我们来看一个例子:
>>> def my_name(): ... def your_name(): ... print('your_name() is two dog') ... print('my_name() is rocky') ... 复制代码
上面就是一个简单的嵌套函数的例子,在上面的代码中,在函数 my_name()
中定义了函数 your_name()
,而 your_name() 就称为 my_name() 的「内嵌函数」,因为它是在 my_name() 里面的定义。
然后我们来调用 my_name(),会得到下面的结果:
>>> my_name() my_name() is rocky 复制代码
这个结果说明在上面的调用方式和内嵌函数的写法中,your_name() 这个函数根本没被调用,或者我们可以这么说,那就是 my_name() 没有按照从上到下的顺序依次执行其里面的代码。
那么我想要 your_name() 这个内嵌函数也执行,该怎么做呢?其实在 my_name() 里面显示的调用一下 your_name() 函数就好了,请看下面的代码:
>>> def my_name(): ... def your_name(): ... print('your_name() is two dog') ... your_name() #显示的调用内嵌函数 ... print('my_name() is rocky') ... 复制代码
我们现在来调用 my_name(),运行结果如下:
>>> my_name() your_name() is two dog my_name() is rocky 复制代码
现在我们再来思考一个问题,我们能不能在 my_name() 外面单独的调用其内嵌函数 your_name() 呢?我们来试一下:
>> your_name() Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'your_name' is not defined 复制代码
结果会显示错误信息,这说明这样调用是不行的,原因就是 your_name() 是定义在 my_name() 里面的函数,它生效的范围仅限于 my_name() 函数体之内,也就是说它的作用域就是 my_name() 的范围而已,既然是这样,那么 your_name 在使用变量的时候也就会收到 my_name() 的约束。
我们再来看一个例子:
>>> def fun1(): ... a = 1 ... def fun2(): ... a += 1 ... print('fun2 -- a = ',a) ... fun2() ... print('fun1 -- a = ',a) ... 复制代码
在看下面的结果之前,请你想一想这个函数的结果会是什么?加入你思考完毕,请看下面的结果:
>>> fun1() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 6, in fun1 File "<stdin>", line 4, in fun2 UnboundLocalError: local variable 'a' referenced before assignment 复制代码
你猜对了么?结果是运行错误!我们观察报错的信息,原因是 fun2() 里面使用了 fun1() 的变量 a,按照表达式, Python 解释器认为这个变量应该在 fun2() 中建立,而不是引用 fun1() 中的变量,所以才报错。
在 Python 中,我们可以使用 nonlocal 这个关键词,具体操作见下例:
>>> def fun1(): ... a = 1 ... def fun2(): ... nonlocal a ... a += 1 ... print('fun2 -- a = ',a) ... fun2() ... print('fun1 -- a = ',a) ... 复制代码
然后我们调用 fun1() 函数,得到如下结果:
fun2 -- a = 2 fun1 -- a = 2 复制代码
综上所述就是嵌套函数的原理,剩下的就是在实践中去运用它,达到加深理解的目的。
这个嵌套函数,其实可以制作动态的函数对象,而这个话题延伸下去,就是所谓的「闭包」。
闭包
我们都知道在数学中有闭包的概念,但此处我要说的闭包是计算机编程语言中的概念,它被广泛的使用于函数式编程。
关于闭包的概念,官方的定义颇为严格,也很难理解,在《Python语言及其应用》一书中关于闭包的解释我觉得比较好 -- 闭包是一个可以由另一个函数动态生成的函数,并且可以改变和存储函数外创建的变量的值 。乍一看,好像还是比较很难懂,下面我用一个简单的例子来解释一下:
>>> a = 1 >>> def fun(): ... print(a) ... >>> fun() 1 >>> def fun1(): ... b = 1 ... >>> print(b) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'b' is not defined 复制代码
毋庸置疑,第一段程序是可以运行成功的,a = 1 定义的变量在函数里可以被调用,但是反过来,第二段程序则出现了报错。
在函数 fun() 里可以直接使用外面的 a = 1,但是在函数 fun1() 外面不能使用它里面所定义的 b = 1,如果我们根据作用域的关系来解释,是没有什么异议的,但是如果在某种特殊情况下,我们必须要在函数外面使用函数里面的变量,该怎么办呢?
我们先来看下面的例子:
>>> def fun(): ... a = 1 ... def fun1(): ... return a ... return fun1 ... >>> f = fun() >>> print(f()) 1 复制代码
如果你仔细看过上面文章的内容,你一定觉得的很眼熟,上述的本质就是我们所讲的嵌套函数。
在函数 fun() 里面,有 a = 1 和 函数 fun1() ,它们两个都在函数 fun() 的环境里面,但是它们两个是互不干扰的,所以 a 相对于 fun1() 来说是自由变量,并且在函数 fun1() 中应用了这个自由变量 -- 这个 fun1() 就是我们所定义的闭包。
闭包实际上就是一个函数,但是这个函数要具有
- 1.定义在另外一个函数里面(嵌套函数);
- 2.引用其所在环境的自由变量。
上述例子通过闭包在 fun() 执行完毕时,a = 1依然可以在 f() 中,即 fun1() 函数中存在,并没有被收回,所以 print(f()) 才得到了结果。
当我们在某些时候需要对事务做更高层次的抽象,用闭包会相当舒服。比如我们要写一个二元一次函数,如果不使用闭包的话相信你可以轻而易举的写出来,下面让我们来用闭包的方式完成这个一元二次方程:
>>> def fun(a,b,c): ... def para(x): ... return a*x**2 + b*x + c ... return para ... >>> f = fun(1,2,3) >>> print(f(2)) 11 复制代码
上面的函数中,f = fun(1,2,3) 定义了一个一元二次函数的函数对象,x^2 + 2x + 3,如果要计算 x = 2 ,该一元二次函数的值,只需要计算 f(2) 即可,这种写法是不是看起来更简洁一些?
当我们在后面学习了类的知识以后,再回过头来看闭包的应用,其实你会有更深的认识,这个我们在后面再做讨论,先知道有类这么一个概念就好了。
写在之后
当然闭包在实际的应用中还有很多方面,作为零基础入门这个系列我们就到此为止,不做深究,可能在后面我会在别的系列中再进一步的讲一下,如果你现在对这个方面很感兴趣,可以 Google 一下这方面的文章,有很多的。
更多内容,欢迎关注公众号「Python空间」,期待和你的交流。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 《JavaScript设计模式与开发实践》基础篇(二)——闭包和高阶函数
- 草根学Python(十五) 闭包(解决一个需求了解闭包流程)
- [原]谈一谈闭包
- Java闭包如何工作
- 理解 JavaScript 闭包
- 管窥python闭包
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。