如何理解及使用Python闭包

作者:Warmer_Sweeter 时间:2021-12-22 23:50:59 

目录
  • 一、Python 中的作用域规则和嵌套函数

  • 二、定义闭包函数

  • 三、何时使用闭包?

  • 四、总结

一、Python 中的作用域规则和嵌套函数

每当执行一个函数时,就会创建一个新的局部命名空间,它表示包含函数体内分配的函数参数和变量名的局部环境。我们可以将名称空间看作一个字典,其中键是对象名称,值是对象本身。

解析名称时,解释器首先搜索本地命名空间。如果不存在匹配,则搜索全局名称空间,该名称空间是定义函数的模块。如果仍然没有找到匹配项,则在引发 NameError 异常之前最终检查内置名称空间。下图说明了这一点:

如何理解及使用Python闭包

让我们考虑下面的例子:


age = 27
def birthday():
 age = 28
birthday()
print(age)  # age will still be 27
>>
27

当变量在函数内部赋值时,它们总是绑定到函数的本地名称空间; 因此,函数体中的变量 age 指的是一个包含值28的全新对象,而不是外部变量。可以使用全局语句更改此行为。下面的示例强调了这一点:


age = 27
name = "Sarah"
def birthday():
 global age       # 'age' is in global namespace
 age = 28
 name = "Roark"
birthday()         # age is now 28. name will still be "Sarah"

Python 也支持嵌套函数定义(函数内部的函数):


def countdown(start):
 # This is the outer enclosing function
 def display():
   # This is the nested function
   n = start
   while n > 0:
     n-=1
     print('T-minus %d' % n)

display()
# We execute the function
countdown(3)
>>>
T-minus 3
T-minus 2
T-minus 1

二、定义闭包函数

在上面的示例中,如果函数 countdown()的最后一行返回了 display 函数而不是调用它,会发生什么情况?这意味着该函数的定义如下:


def countdown(start):
 # This is the outer enclosing function
 def display():
   # This is the nested function
   n = start
   while n > 0:
     n-=1
     print('T-minus %d' % n)
 return display
# Now let's try calling this function.
counter1 = countdown(2)
counter1()
>>>
T-minus 2
T-minus 1

使用值2调用 countdown()函数,并将返回的函数绑定到名称 counter1。在执行 counter1()时,它使用最初提供给 countdown ()的 start 值。因此,在调用 counter1()时,尽管我们已经执行了 count1()函数,但仍然记住这个值。

这种将一些数据(本例中为2)附加到代码的技术在 Python 中称为闭包。

即使变量超出范围或函数本身从当前名称空间中移除,也会记住封闭范围中的这个值。我们可以尝试下面的代码来确认:


>>> del countdown
>>> counter1()
T-minus 2
T-minus 1
>>> countdown(2)
Traceback (most recent call last):
...
NameError: name 'countdown' is not defined

三、何时使用闭包?

当一个类中实现的方法很少(大多数情况下只有一个方法)时,闭包可以提供一个替代的、更优雅的解决方案。此外,如果我们希望根据延迟或延迟计算的概念编写代码,闭包和嵌套函数特别有用。下面是一个例子:


from urllib.request import urlopen
def page(url):
 def get():
   return urlopen(url).read()
 return get

在上面的示例中,page ()函数实际上并不执行任何计算。相反,它只是创建并返回一个函数 get () ,该函数在调用 web 页面时获取页面内容。因此,在 get ()中执行的计算实际上被延迟到计算 get ()时程序中的某个后续点。例如:


>>> url1 = page("http://www.google.com")
>>> url2 = page("http://www.bing.com")
>>> url1
<function page.<locals>.get at 0x10a6054d0>
>>> url2
<function page.<locals>.get at 0x10a6055f0>

>>> gdata = url1()     # Fetches http://www.google.com
>>> bdata = url2()     # Fetches http://www.bing.com
>>>

可以找到闭包函数中包含的值。

所有函数对象都有一个 _closure_ 属性,如果它是一个闭包函数,那么这个属性将返回一组单元格对象。根据上面的例子,我们知道 url1和 url2是闭包函数。


>>> page.__closure__       # Returns None since not a closure
>>> url1.__closure__
(<cell at 0x10a5f1250: str object at 0x10a5f3120>,)

单元格对象具有存储关闭值的属性 cell_contents。


>>> url1.__closure__[0].cell_contents
'http://www.google.com'
>>> url2.__closure__[0].cell_contents
'http://www.bing.com'

四、总结

当嵌套函数引用其封闭范围中的值时,可以定义 Python 中的闭包。闭包提供了某种形式的数据隐藏。闭包还可以是一种高效的方法,可以在一系列函数调用之间保持状态。用 Python 创建一个闭包函数:

  • 我们必须有一个嵌套的函数

  • 嵌套函数必须引用封闭函数中定义的值

  • 封闭函数必须返回嵌套函数

来源:https://blog.csdn.net/weixin_38739735/article/details/117393726

标签:Python,闭包
0
投稿

猜你喜欢

  • Yii2 rbac权限控制操作步骤实例教程

    2024-05-22 10:02:18
  • Django 缓存配置Redis使用详解

    2021-12-27 12:34:32
  • CSS实例教程:复合型CSS条状图表(上)

    2010-01-23 12:43:00
  • MySQL常见错误有哪些_MySQL常见错误的快速解决方法

    2024-01-25 09:16:31
  • canvas实现手机端用来上传用户头像的代码

    2023-09-16 02:30:54
  • Python3.7将普通图片(png)转换为SVG图片格式(网站logo图标)动起来

    2021-09-26 00:05:53
  • 基于python实现MQTT发布订阅过程原理解析

    2023-05-06 14:45:14
  • golang之log rotate详解

    2024-02-03 10:54:45
  • python中的不可变数据类型与可变数据类型详解

    2022-12-27 21:56:24
  • python pip源配置,pip配置文件存放位置的方法

    2023-01-25 09:51:46
  • 详解Go 依赖管理 go mod tidy

    2024-05-02 16:25:17
  • Django 后台获取文件列表 InMemoryUploadedFile的例子

    2021-09-25 11:19:38
  • Python列表生成器的循环技巧分享

    2023-10-06 21:24:28
  • js实时监听文本框状态的方法

    2024-04-25 13:10:58
  • MySQL之导出整个及单个表数据的操作

    2024-01-17 00:52:02
  • 一文读懂python Scrapy爬虫框架

    2021-01-31 10:08:31
  • 基于Pytorch实现的声音分类实例代码

    2021-01-04 21:42:28
  • Python+Pygame实现怀旧游戏飞机大战

    2023-09-27 03:36:52
  • vue中的Object.freeze() 优化数据方式

    2024-04-10 16:10:25
  • pycharm无法安装cv2模块问题及解决方案

    2023-02-14 21:20:49
  • asp之家 网络编程 m.aspxhome.com