python闭包和装饰器(转)
一、python闭包
1、内嵌函数
- >>> def func1():
- ... print ('func1 running...')
- ... def func2():
- ... print ('func2 running...')
- ... func2()
- ...
- >>> func1()
- func1 running...
- func2 running...
内部函数func2作用域都在外部函数func1作用域之内
如果试图在外部函数的外部调用内部函数将会报错
- >>> func2()
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- NameError: name 'func2' is not defined
如果试图在一个内部函数里对外部作用域(不包括外部函数的外部作用域)的变量进行引用,内部函数就会被认为是闭包
- >>> def FuncX(x):
- ... def FuncY(y):
- ... return x*y
- ... return FuncY
对于FuncY函数来说,对在FuncX函数的整个作用域(FuncY函数的非全局作用域的外部作用)的变量x进行引用,自此就可以说FuncY函数就是所谓的闭包
- >>> f = FuncX(8)
- >>> f
- <function FuncY at 0x7f3a436fc2a8>
- >>> type(f)
- <type 'function'>
- >>> f(10)
- 80
- >>> FuncX(7)(8)
- 56
由于闭包本身是基于内部函数这一概念而来,所以不能在外部函数的外部作用域对内部函数进行调用
- >>> FuncY(8)
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- NameError: name 'FuncY' is not defined
既然是基于内部函数这一概念而来,自然对于内部函数来说对引用外部函数作用域内的变量进行修改,将会启动解释器的屏蔽机制
- >>> def Func1():
- ... x = 233
- ... def Func2():
- ... x *=x
- ... return x
- ... return Func2()
- ...
- >>> Func1()
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- File "<stdin>", line 6, in Func1
- File "<stdin>", line 4, in Func2
- UnboundLocalError: local variable 'x' referenced before assignment
x*=x的左值此时是内部函数作用域里的变量,此时试图将没有定义的数据进行平方操作,因此报错
- >>> def Func1():
- ... x = 233
- ... def Func2():
- ... x = 321
- ... return x
- ... return Func2()
- ...
- >>> Func1()
- 321
内部函数创建x变量并且屏蔽外部函数作用域内的x变量
python3之前的解决办法
应用容器类型(list,tuple之类的)存放外部函数作用域的变量从而不会被屏蔽机制屏蔽掉,因为容器类型不是存放在栈里面
- >>> def Func1():
- ... x = [233]
- ... def Func2():
- ... x[0] *= x[0]
- ... return x[0]
- ... return Func2()
- ...
- >>> Func1()
- 54289
python3之后的解决办法:nonlocal关键字
- >>> def Func1():
- ... x = 233
- ... def Func2():
- ... nonlocal x
- ... x *= x
- ... return x
- ... return Func2()
- ...
- >>> Func1()
- 54289
二、装饰器
事实上,装饰器就是一种的闭包的应用,只不过其传递的是函数:
@makeitalic 装饰器将函数 hello 传递给函数 makeitalic,函数 makeitalic 执行完毕后返回被包装后的 hello 函数,而这个过程其实就是通过闭包实现的。@makebold 也是如此,只不过其传递的是 @makeitalic 装饰过的 hello 函数,因此最后的执行结果 <b>
在 <i>
外层,这个功能如果不用装饰器,其实就是显式的使用闭包:
闭包的作用
闭包的最大特点是可以将父函数的变量与内部函数绑定,并返回绑定变量后的函数(也即闭包),此时即便生成闭包的环境(父函数)已经释放,闭包仍然存在,这个过程很像类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活,现举一例:假设我们仅仅想打印出各类动物的叫声,分别以类和闭包来实现:
可以看到输出结果是完全一样的,但显然类的实现相对繁琐,且这里只是想输出一下动物的叫声,定义一个 Animal 类未免小题大做,而且 voice 函数在执行完毕后,其作用域就已经释放,但 Animal 类及其实例 dog 的相应属性却一直贮存在内存中:
而这种占用对于实现该功能后,则是没有必要的。
除此之外,闭包还有很多其他功能,比如用于封装等,另外,闭包有效的减少了函数参数的数目,这对并行计算非常有价值,比如可以让每台电脑负责一个函数,然后串起来,实现流水化的作业等。
转自:http://blog.csdn.net/ChangerJJLee/article/details/52598629
https://segmentfault.com/a/1190000004461404
python闭包和装饰器(转)的更多相关文章
- python 闭包和装饰器
python 闭包和装饰器 一.闭包闭包:外部函数FunOut()里面包含一个内部函数FunIn(),并且外部函数返回内部函数的对象FunIn,内部函数存在对外部函数的变量的引用.那么这个内部函数Fu ...
- python闭包与装饰器
转自小马哥: 闭包和装饰器充分体现了Python语法糖的优雅感觉. 在本文中,我们的实验要完成两个工作,一个是加法,一个是累计调用加法的次数,最普通的Python程序可以这么写: def valida ...
- 高逼格利器之Python闭包与装饰器
生活在魔都的小明,终于攒够了首付,在魔都郊区买了一套房子:有一天,小明踩了狗屎,中了一注彩票,得到了20w,小明很是欢喜,于是想干脆用这20万来装修房子吧(decoration): 整个装修过程,小明 ...
- Python—闭包和装饰器
闭包 定义:内部函数对外部函数变量的引用,则将该函数与用到的变量称为闭包. 闭包必须满足以下三个条件: 必须有一个内嵌函数. 内嵌函数必须引用外部函数中的变量. 外部函数返回值必须是内嵌函数的引用. ...
- Python 简明教程 --- 22,Python 闭包与装饰器
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 当你选择了一种语言,意味着你还选择了一组技术.一个社区. 目录 本节我们来介绍闭包与装饰器. 闭包与 ...
- Python闭包及装饰器
Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们 ...
- python闭包以及装饰器
通俗的定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).它只不过是个“内层”的函数,由一个名字(变量)来指代,而这个名字(变 ...
- python闭包和装饰器
本文目录: 1. 闭包的解析和用法 2. 函数式装饰器 3. 类装饰器 一.闭包 闭包是一种函数,从形式上来说是函数内部定义(嵌套)函数,实现函数的扩展.在开发过程中,考虑到兼容性和耦合度问题,如果想 ...
- 详解Python闭包,装饰器及类装饰器
在项目开发中,总会遇到在原代码的基础上添加额外的功能模块,原有的代码也许是很久以前所写,为了添加新功能的代码块,您一般还得重新熟悉源代码,稍微搞清楚一点它的逻辑,这无疑是一件特别头疼的事情.今天我们介 ...
随机推荐
- 实验 1 Java 运行环境的安装、配置与运行
一.实验目的 1. 掌握下载 Java SDK 软件包. 2. 掌握设置 Java 程序运行环境的方法. 3. 掌握编写与运行 Java 程序的方法. 4. 了解 Ja ...
- win7/win8/win10 php5.6 redis扩展(适用于iis/nginx/apache),亲测
win7 php5.6 redis扩展 步骤: 1.下载redis扩展 redis扩展下载地址:http://windows.php.net/downloads/pecl/snaps/redis/ ...
- 如何制作Jar包并在android中调用jar包
android制作jar包: 新建android工程,然后右击,点击导出,选择导出类型为Java下的JAR file,在java file specification 中不要选择androidmani ...
- 纯文本文件 student.txt为学生信息, 里面的内容(包括花括号)如下所示
import json from collections import OrderedDict import xlwt with open('student.txt',encoding='utf-8' ...
- RegExp实例
ECMAScript通过RegExp类型来支持正则表达式,常见的正则表达式为:var expression = /pattern / flags;其中的模式(pattern)部分可以使任何简单或复杂的 ...
- Java设计原则之里氏替换原则
里氏代换原则由2008年图灵奖得主.美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出.其严格表述如下:如果对每一个类型为S的 ...
- [转]C#调用Excel VBA宏
[转载自]http://www.shangxueba.com/jingyan/95031.html 附上一段原创常用代码 计算列标题字符串 Function CalcColumn(ByVal c As ...
- sentinel服务器出现大量的连接问题【转载】
一.问题现象 redis服务端的sentinel模块存在大量的established状态的连接,并且这些连接一直不被释放,而客户端的连接数正常. 二.问题排查过程 1.根据连接状态进行推断 服务端存在 ...
- java的super和this关键字用法总结
------super关键字------ super用途:在子类中访问超类“被隐藏的成员变量(无论是否静态)和静态方法”以及“被重写的实例方法”.这里的超类必须是“直接 ...
- 用深度学习LSTM炒股:对冲基金案例分析
英伟达昨天一边发布“全球最大的GPU”,一边经历股价跳水20多美元,到今天发稿时间也没恢复过来.无数同学在后台问文摘菌,要不要抄一波底嘞? 今天用深度学习的序列模型预测股价已经取得了不错的效果,尤其是 ...