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. java第四次面试总结

    该公司没有笔试,直接就进行了面试,然后我就拿着我的简历瑟瑟发抖...... 1.因为是看简历来面试,所以面试官从我的项目下手,而我的项目都是后端的东西,虽然学过一些前端,但是项目里并没有用到任何jav ...

  2. 修改CentOS默认yum源为国内镜像

    参考文档 https://blog.csdn.net/inslow/article/details/54177191 国内主要开源的开源镜像站点应该是网易和阿里云了. 修改为163yum源-mirro ...

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

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

  4. 过渡属性transition

    过渡属性:使元素变化过程可见 transition: all 1s;元素所有变化过程都可见 transition: 1s;元素所有变化过程都可见 transition: 指定属性 2s 1s;指定属性 ...

  5. Node学习之(第三章:仿Apache显示目录列表的功能)

    前言 今天咱们用Node.js中的核心模块以及上节学习的模板引擎art-template来实现服务器软件Apache的大体功能.用过Apache的朋友都知道,我们只需把本地文件放置在Apache的ww ...

  6. Vivado debug异常现象

    前言 bit文件和ltx文件的信号位宽不匹配问题.用了dont_touch等属性没用... WARNING: [Labtools 27-1972] Mismatch between the desig ...

  7. mysql学习之基础篇06

    子查询:又分为where型子查询,from型子查询,exists型子查询这三类. where型子查询:指把内层查询的结果作为外层查询的比较条件: 举个例子: 我们想查出goods_id最大的商品,要求 ...

  8. IP positioning check position

    1.如何找到网上散布不法言论的人的地理位置 比方像微博发布的时候都会自动添加主机网络地址,需要对头文件进行分析 找到IP地址 然后进行反查IP地址的位置 , 如果是可以与要查的终端可以进行通信 ,可以 ...

  9. ts介绍

    typescript是微软开发的一门编程语言,它是javascrip的一个超集,它遵循最新的es6脚本语言规范,typescript扩展了javascript的语法,任何已经存在的javascipt程 ...

  10. 项目(二)--完成练手feed流网站开发部署

    样式需要优化,最简版,还需新增逻辑. 点击跳转 源码