def bibao():
li = []
n = [1]
def inner():
li.append(n[0])
n[0] +=1
print(li)
return inner b = bibao()
b()
b()
结果分别为[1]和[1,2]

1.简述

内部函数被当做对象返回时,夹带了这个内部函数之外的自由变量

闭包:带着当前变量环境的函数

b是inner函数,具有当前变量的值,li是一个空列表,n=[1]

b(),当b被调用时,li.append(1),n=[2],li=[1],这些变量都被存储在了__closure__中

b.__closure__返回值是一个列表,包含自由变量li和n的值

2.典型错误

def wrapper():
n = 1
def inner():
n += 1
print(n)
return inner
w = wrapper()
w()
w()

运行时会抛出异常

UnboundLocalError: local variable 'n' referenced before assignment

原因是n=n+1时将n变为局部变量,不再是inner函数外的自由变量,可以通过下面的例子证明

1.不在inner内部对n进行赋值时,n仍然为外部变量

def wrapper():
n = 1
def inner():
print(n)
return inner
w = wrapper()
w()
print(w.__closure__)

打印结果为:(<cell at 0x101dc92b8: int object at 0x100983c20>,)

证明此时是有外部变量的

2.在inner内部对n进行赋值时,n变为局部变量

def wrapper():
n = 1
def inner():
n = 1
print(n)
return inner
w = wrapper()
w()
print(w.__closure__)

打印结果为:None

证明此时n变为了局部变量

3.针对2中的错误,解决办法

使用 nonlocal将n的属性变为不是局部变量

def wrapper():
n = 1
def inner():
nonlocal n
n = n + 1
print(n)
return inner
w = wrapper()
w()
print(w.__closure__)

(<cell at 0x101dc92b8: int object at 0x100983c40>,)

打印结果中又有自由变量了

nonlocal表示n不是局部变量,不改变它的属性

4.注意

4.1 具体参考python官网:https://www.python.org/dev/peps/pep-3104/

4.2 如果在自由变量中未声明,直接在函数内部使用的nonlocal,会报错

def wrapper():
n = 1
def inner():
nonlocal n
n = n + 1
print(n)
m = 1
nonlocal m
return inner
w = wrapper()
w()
print(w.__closure__)

如上代码会报错

SyntaxError: name 'm' is assigned to before nonlocal declaration

m必须先是声明为自由变量

5.装饰器与@

pass

python基础-闭包的更多相关文章

  1. python基础--闭包and装饰器

    闭包函数:函数内部定义的函数:引用了外部变量但非全局变量 装饰器:有了闭包的概念再去理解装饰器就会相对容易一些.python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加 ...

  2. python基础--闭包、装饰器

    装饰器的详细使用 (1)小知识点补充 在这里我们先学一个简单的知识点. li = ['alex', '银角', '女神', 'egon', '太白'] for i in enumerate(li): ...

  3. python基础-闭包函数和装饰器

    闭包函数和装饰器 闭包函数 概念:在函数中(嵌套)定义另一个函数时,内部函数引用了外层函数的名字. 特性 闭包函数必须在函数内部定义 闭包函数可引用外层函数的名字 闭包函数是函数嵌套.函数对象.名称空 ...

  4. python基础—函数嵌套与闭包

    python基础-函数嵌套与闭包 1.名称空间与作用域 1 名称空间分为: 1 内置名称空间   内置在解释器中的名称 2 全局名称空间   顶头写的名称 3 局部名称空间 2 找一个名称的查找顺序: ...

  5. Python基础+Pythonweb+Python扩展+Python选修四大专题 超强麦子学院Python35G视频教程

    [保持在百度网盘中的, 可以在观看,嘿嘿 内容有点多,要想下载, 回复后就可以查看下载地址,资源收集不易,请好好珍惜] 下载地址:http://www.fu83.cc/ 感觉文章好,可以小手一抖 -- ...

  6. python基础——返回函数

    python基础——返回函数 函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回.  我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_ ...

  7. Python基础:函数式编程

    一.概述 Python是一门多范式的编程语言,它同时支持过程式.面向对象和函数式的编程范式.因此,在Python中提供了很多符合 函数式编程 风格的特性和工具. 以下是对 Python中的函数式编程 ...

  8. python基础教程

    转自:http://www.cnblogs.com/vamei/archive/2012/09/13/2682778.html Python快速教程 作者:Vamei 出处:http://www.cn ...

  9. python基础—函数装饰器

    python基础-函数装饰器 1.什么是装饰器 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能. 装饰器的返回值是也是一个函数对象. 装饰器经常用于有切 ...

随机推荐

  1. Paper Read: Convolutional Image Captioning

    Convolutional Image Captioning 2018-11-04 20:42:07 Paper: http://openaccess.thecvf.com/content_cvpr_ ...

  2. 论文笔记:Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks

    Model-Agnostic Meta-Learning for Fast Adaptation of Deep Networks ICML 2017 Paper:https://arxiv.org/ ...

  3. 【Visual Studio 扩展工具】使用ComponentOne中的GroupDefinition和SortDefinition属性保存和还原布局

    概述 在此前的ComponentOne中,我们为C1FlexGrid(最快,最灵活的.Net数据网格控件)添加了一个非常强大的动态分组功能,这篇技术博客<将动态分组添加到.NET表格控件Flex ...

  4. 网络3-Jsonp

    解决跨域问题的几种办法 1.Flash (不做讨论) 2.服务器代理中转 3.Jsonp 4.document.domain(针对基础域名相同的情况)bj.58.com document.domain ...

  5. App自动更新(DownloadManager下载器)

    一.开门见山 代码: object AppUpdateManager { const val APP_UPDATE_APK = "update.apk" private var b ...

  6. Angular 学习笔记 (Material Datepicker)

    https://material.angular.io/components/datepicker/overview 官网介绍很清楚了,这里记入一下我比较不熟悉的. 1. moment js Angu ...

  7. LINUX介绍

    Linux操作系统被称为领先的服务器操作系统之一,它被普遍和广泛使用着.全球大约有数百款的Linux系统版本,每个系统版本都有自己的特性和目标人群. Linux的发行版本可以大体分为两类,一类是商业公 ...

  8. Eclipse调试多线程代码

    Eclipse调试多线程代码 标签: eclipse 调试 多线程 | 发表时间:2013-02-16 05:51 | 作者:czjuttsw 分享到: 出处:http://blog.csdn.net ...

  9. 阶段01Java基础day24多线程+GUI

    25.01_多线程(多线程方法) 1.yield让出cpu 2.setPriority()设置线程的优先级 25.02_多线程(单例设计模式)(掌握) 单例设计模式:保证类在内存中只有一个对象. 如何 ...

  10. 查询系统正在运行的SQL语句

    查询系统正在运行的SQL语句: select a.program, b.spid, c.sql_text from v$session a, v$process b, v$sqlarea c wher ...