美文网首页python自学Python
Python中的闭包是什么?

Python中的闭包是什么?

作者: 苦逼李 | 来源:发表于2018-04-10 20:21 被阅读9次

目录

  • 作用域(scope)
  • 闭包的定义
  • 闭包的作用
  • 总结

2018.4.15
更新了对于函数作用域的理解内容

1.作用域

作用域限定了一个变量在程序中的有效范围,对于一个函数,其内部定义的变量的作用域就是这个函数体内部,一旦函数结束被调用,此变量将被析构。简言之,函数中定义的变量称作局部变量,它只能在函数内部被引用。

下面的例子说明了局部变量不能在函数外访问:

In [9]: def f1():
   ...:     a = 1
   ...:

In [10]: print(a)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-10-bca0e2660b9f> in <module>()
----> 1 print(a)

NameError: name 'a' is not defined

而在所有函数之外定义的变量可以被函数访问:

In [12]: b = 1

In [13]: def f2():
    ...:     print(b)
    ...:

In [14]: f2()
1

另外,由于Python支持函数的嵌套,按照函数的作用域原则,内函数可以访问外函数定义的变量:

In [37]: def f1():
    ...:     x = 1
    ...:     def f2():
    ...:         print(x)
    ...:     f2()
    ...:

In [38]: f1()
1

2.闭包的定义

我们将上一个代码稍作修改:

In [50]: def f1():
    ...:     x = 1
    ...:     def f2():
    ...:         print(x)
    ...:     return f2
    ...:

In [51]: m = f1()

In [52]: n = f1()

In [53]: m == n
Out[53]: False
    
In [54]: m()
Out [54]: 1
  • 从上面的例子可以看出,f1每次返回的函数都不同。
  • 还有一个隐含特性,在In [54]: x()这条代码中,尽管随着函数f1()被调用,参数x的作用域已经结束,然而函数m仍然可以正常的引用参数x,这表明了内嵌函数可以引用外部函数的参数,并且当这些参数的作用域随着外部函数的调用结束后仍然能被内嵌函数引用。

通过上述的例子,我们再引入Wiki百科的对于闭包的定义:

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

如果要在内嵌函数中修改引用的外部变量,需要在内嵌函数中对要修改的变量使用nonlocal关键字进行声明:

In [58]: def creatCounter():    # 实现一个加法器 每次调用内嵌函数就加一
    ...:     i = 0
    ...:     def count():
    ...:         nonlocal i     # nonlocal关键字标志着内嵌函数将修改外部变量 如果没有这行代码将会出错
    ...:         i += 1
    ...:         return i
    ...:     return count
    ...:

In [59]: f = creatCounter()

In [60]: f()
Out[60]: 1

In [61]: f()
Out[61]: 2

In [62]: f()
Out[62]: 3

3.闭包的作用

闭包避免使用了全局变量,闭包允许将某些数据和函数关联起来,这一点很像类。在面向对象过程中,我们将定义了一些属性,并将它们与一些方法关联起来。如果要定义只用一个方法的类,可以采用闭包的方法实现。另外,闭包在装饰器中也很重要。

判断一个函数是不是闭包,可以查看它的closure属性,如果是闭包,查看该属性将会返回一个cell对象组成的元组,分别对每个cell对象查看其cell_contents属性,返回的内容就是闭包引用的自由变量的值。下面通过一个例子展示:

In [41]: def add(x,y):
    ...:     def f(z):
    ...:         return x+y+z
    ...:     return f
    ...:

In [42]: d = add(5,5)

In [43]: d(9)
Out[43]: 19

In [44]: d(1)
Out[44]: 11

In [45]: d.__closure__      # 闭包的__closure__属性
Out[45]:
(<cell at 0x000001F9A295CCD8: int object at 0x000000006F666140>,
 <cell at 0x000001F9A295C9A8: int object at 0x000000006F666140>)

In [46]: for i in d.__closure__:
    ...:     print(i.cell_contents)   # 查看每个cell对象的内容 —— cell_contents属性
    ...:
5
5
  • cell_contents解释了局部变量在脱离函数后仍然可以在函数之外被访问,因为变量被存储在cell_contents中了。

4.总结

  • 在python的作用域规则里面,创建变量一定会在当前作用域里创建一个变量,但是访问或者修改变量时会先在当前作用域查找变量,没有找到匹配变量的话会依次向上在闭合的作用域里面进行查找。
  • 在内嵌函数中使用nonlocal关键字对外部变量进行声明,可以允许内嵌函数修改外部变量。
  • 闭包是引用了自由变量的函数。
  • 闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
  • 闭包中包含了内部函数的代码,以及所需外部函数中的变量的引用。其中所引用的变量称作上值(upvalue)。
  • 判断一个函数是不是闭包,可以查看它是否存在closure属性
  • closure属性是一个包含若干个cell对象的元组,每个cell对象的cell_content属性分别代表一个自由变量的值。

结语:这篇文章更多的只是作为学习笔记,其中参考了网上一些前辈的文章或是其他资料,所以有些可能会大量引用,如有冒犯,请私信我,还望谅解。

相关文章

  • python函数之闭包

    目录 python函数之闭包什么是闭包python中的namespace闭包的条件闭包的优点 python函数之闭...

  • Python 闭包使用注意点

    1 Python 闭包 今天,聊下 python 的闭包。在函数编程中经常用到闭包。 闭包是什么,它是怎么产生的及...

  • python闭包学习

    参考文章 python闭包python闭包一步一步教你认识Python闭包深入浅出python闭包

  • Python 中的闭包

    Python 中的闭包:+ http://python.jobbole.com/82296/

  • Python中的闭包是什么?

    目录 作用域(scope) 闭包的定义 闭包的作用 总结 2018.4.15更新了对于函数作用域的理解内容 1.作...

  • 前端常见问题总结

    什么是闭包?闭包的用途是什么?闭包的缺点是什么? 什么是闭包 闭包:内部函数总是可以访问其所在的外部函数中声明的参...

  • Python闭包与ObjC的block的区别与联系

    首先明确一下Python闭包和ObjC中block的定义在python中闭包是这么定义的——内层函数引用了外层函数...

  • 彻底理解JS闭包

    闭包并不是JS所独有的,在计算机科学中其是一个普遍的概念,在Python中也有闭包的概念,但闭包在Python应用...

  • JavaScript 中 闭包 的详解

    闭包是什么 在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭...

  • JavaScript 中的闭包

    闭包是什么 在 JavaScript 中,闭包是一个让人很难弄懂的概念。ECMAScript 中给闭包的定义是:闭...

网友评论

本文标题:Python中的闭包是什么?

本文链接:https://www.haomeiwen.com/subject/seznhftx.html