零基础学习 Python 之闭包

栏目: Python · 发布时间: 5年前

内容简介:在正式讲「闭包」之前我们首先得先知道「嵌套函数」这么一个东西,我在之前的文章中(首先我们来看一个例子:上面就是一个简单的嵌套函数的例子,在上面的代码中,在函数

在正式讲「闭包」之前我们首先得先知道「嵌套函数」这么一个东西,我在之前的文章中( 零基础学习 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空间」,期待和你的交流。

零基础学习 Python 之闭包

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Algorithms for Image Processing and Computer Vision

Algorithms for Image Processing and Computer Vision

Parker, J. R. / 2010-12 / 687.00元

A cookbook of algorithms for common image processing applications Thanks to advances in computer hardware and software, algorithms have been developed that support sophisticated image processing with......一起来看看 《Algorithms for Image Processing and Computer Vision》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具