1. 什么是闭包:

  闭包 是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。 

 

2. 形成闭包的条件:

  1. 该函数体的整体类型为高阶函数(解释:一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归),满足其一则为高阶函数)

  2. 内部函数引用了自由变量(该变量可以是外部函数的形参, 也可以是外部函数的局部变量)

  通俗来说就是定义在某一个函数内部的函数

3. 实现

  1. 下面来举一个简单的闭包(不修改变量outer_var,只做读取)例子:

def outer():
outer_var = 1
def inner():
inner_var = outer_var + 100
print('inner:\t%s' % inner_var)
return inner

  执行结果如下:  

  

  但是从变量的生存周期来看,该怎么理解呢?我们的变量outer_var是函数outer的一个本地变量,这意味着只有当函数outer正在运行的时候才会存在。根据我们已知的python运行模式,我们没法在函数outer返回之后继续调用函数inner,在函数inner被调用的时候,变量outer_var早已不复存在,可能会发生一个运行时错误。然而返回的函数inner居然能够正常工作。Python支持一个叫做函数闭包的特性,用人话来讲就是,嵌套定义在非全局作用域里面的函数能够记住它在被定义的时候它所处的封闭命名空间。这能够通过查看函数的func_closure属性得出结论,这个属性里面包含封闭作用域里面的值(只会包含被捕捉到的值,比如outer_var,如果在outer里面还定义了其他的值,封闭作用域里面是不会有的)记住,每次函数outer被调用的时候,函数inner都会被重新定义。现在变量outer_var的值不会变化,所以每次返回的函数inner会是同样的逻辑

  2. 通过子函数修改父函数的自由变量

  在实现该功能之前不得不提及两个关键字, global及nonlocal

# global
GLOABL_BASE = 100

def increaseNum1():
GLOABL_BASE = 99
print(GLOABL_BASE, id(GLOABL_BASE)) def increaseNum2():
global GLOABL_BASE
GLOABL_BASE = 99
print(GLOABL_BASE, id(GLOABL_BASE)) if __name__ == '__main__':
print("*"*30)
increaseNum1()
print(GLOABL_BASE, id(GLOABL_BASE))
print("*" * 30)
increaseNum2()
print(GLOABL_BASE, id(GLOABL_BASE))

可以发现, 函数体内部的GLOBAL_BASE为该函数内部的局部变量, 模块级别下的GLOBAL_BASE与该函数作用域不产生共享,如果将函数内的变量声明为模块级别, 那么就实现了修改全局变量的功能

  那么在闭包环境下,如果修改外部函数中的变量呢?

def outer(init_num):
print("outer:\t{0}".format(init_num))
def inner(step):
nonlocal init_num
init_num += step
print("inner:\t{0}".format(init_num))
return inner if __name__ == '__main__':
func = outer(0)
for step in range(3):
func(2)
print("*"*30)
for step in range(3):
outer(0)(2)
print("*" * 30)

解释: 修改变量的作用域级别实现了, 但为什么运行期间保留了父函数中的变量值,这正是闭包,父函数会等待子函数调用彻底结束时才会释放空间,这里的func对象的生命周期直到最后一次被执行(函数对象同样具备__call__方法)才释放。

3. 剖析相关概念

  1. 作用域:我们知道对于一个模块来说, 其可能包含函数、类等抽象结构, 宏观上来看, 一个模块划分了多个作用域, 且是层层包含的关系, 那么在一个函数内部的命名空间内当出现一个变量的引用时,他会优先在自己的命名空间内查找该变量,这里我们就以全局作用域以及局部作用域为例,来做一下验证

# -*- coding:utf-8 -*-
"""测试作用域"""
GLO = 100
def local_func():
LOC = 1
print(locals()) def main():
for k, v in globals().items():
print(k,v)
print("*"*30)
local_func() if __name__ == '__main__':
main()

  2.

  

4. 闭包的内存模型

浅谈python闭包及装饰器的更多相关文章

  1. python 闭包和装饰器

    python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...

  2. python闭包与装饰器

    转自小马哥: 闭包和装饰器充分体现了Python语法糖的优雅感觉. 在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写: def valida ...

  3. 高逼格利器之Python闭包与装饰器

    生活在魔都的小明,终于攒够了首付,在魔都郊区买了一套房子:有一天,小明踩了狗屎,中了一注彩票,得到了20w,小明很是欢喜,于是想干脆用这20万来装修房子吧(decoration): 整个装修过程,小明 ...

  4. Python—闭包和装饰器

    闭包 定义:内部函数对外部函数变量的引用,则将该函数与用到的变量称为闭包. 闭包必须满足以下三个条件: 必须有一个内嵌函数. 内嵌函数必须引用外部函数中的变量. 外部函数返回值必须是内嵌函数的引用. ...

  5. Python 简明教程 --- 22,Python 闭包与装饰器

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 当你选择了一种语言,意味着你还选择了一组技术.一个社区. 目录 本节我们来介绍闭包与装饰器. 闭包与 ...

  6. Python闭包及装饰器

    Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们 ...

  7. python闭包以及装饰器

    通俗的定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).它只不过是个“内层”的函数,由一个名字(变量)来指代,而这个名字(变 ...

  8. 浅显易懂的谈一谈python中的装饰器!!

    hello大家好~~我是稀里糊涂林老冷,一天天稀里糊涂的. 前一段时间学习了装饰器,觉着这东西好高大上哇靠!!哈哈,一定要总结一下,方便以后自己查阅,也希望帮助其他伙伴们共同进步! 装饰器: 大家可以 ...

  9. python闭包和装饰器

    本文目录: 1. 闭包的解析和用法 2. 函数式装饰器 3. 类装饰器 一.闭包 闭包是一种函数,从形式上来说是函数内部定义(嵌套)函数,实现函数的扩展.在开发过程中,考虑到兼容性和耦合度问题,如果想 ...

随机推荐

  1. C语言开发中常用英文缩写

    BIOS(Basic Input Output System): 基本输入输出系统 reference: https://baike.baidu.com/item/bios/91424?fr=alad ...

  2. 【转载】Javascript使用Math.random()随机数函数生成1至1000的随机数

    在Javascript代码编写过程中,有时候我们需要使用Js来生成随机数,清除ajax的get请求缓存的时候我们会带上一个随机数来解决此问题,此外在其他应用中也可能使用到随机数,在Javascript ...

  3. UCOS内存管理

    STM32F10xxx内置64K字节的静态SRAM.它可以以字节.半字(16位)或全字(32位)访问 SRAM的起始地址是0x20000000 UCOSII //定义存储区 OS_MEM *DATA_ ...

  4. MySQL Backup--Xtrabackup备份常见错误

    1.DDL操作与Xtrabackup备份冲突 当MySQL使用xrabckup进行备份时,如果执行DDL进行表修改,会导致xrabckup备份失败. 错误类似于: InnoDB: Last flush ...

  5. keepalived实现nginx反向代理的高可用

    实现keepalived调用脚本进行资源监控 keepalived调用外部的辅助脚本进行资源监控,并根据监控的结果状态能实现优先动态调整 vrrp_script:自定义资源监控脚本,vrrp实例根据脚 ...

  6. 大数据技术之Hadoop3.1.2版本伪分布式部署

    大数据技术之Hadoop3.1.2版本伪分布式部署 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.主机环境准备 1>.操作系统环境 [root@node101.yinzh ...

  7. 安装CDH 5.15.1详解

    安装CDH 5.15.1详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  一.安装Cloudera Manager 和CDH 1>.登陆Cloudera Manager ...

  8. java基础(7)---IO流

    一.FileWriter 导包:import java.io.FileWriter 覆盖写入: 追加写入:  写数据换行:  write方法重载: 二.编码: 三.FileReader: read重载 ...

  9. python3 queue队列

    一.queue队列 1.python3中的队列模块是queue,不是Queue 2.一般涉及到同步,多线程之类用到队列模块 3.定义了 queue.Queue 类,以及继承它的 queue.LifoQ ...

  10. Kotlin扩展深入解析及注意事项和可见性

    可见性[Visibility]: 在Java中的可见性有public.protected.private.default四种,而在Kotlin中也有四种:public.protected.privat ...