python教程闭包_Python教程 闭包的特性

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

闭包(closure)是函数式编程的重要的语法结构。函数式编程是一种编程范式 (而面向过程编程和面向对象编程也都是编程范式)。在面向过程编程中,我们见到过函数(function);在面向对象编程中,我们见过对象(object)。函数和对象的根本目的是以某种逻辑方式组织代码,并提高代码的可重复使用性(reusability)。闭包也是一种组织代码的结构,它同样提高了代码的可重复使用性。

不同的语言实现闭包的方式不同。Python以函数对象为基础,为闭包这一语法结构提供支持的 (我们在特殊方法与多范式»http://www.cnblogs.com/vamei/archive/2012/11/19/2772441.html✔ 中,已经多次看到Python使用对象来实现一些特殊的语法)。Python一切皆对象,函数这一语法结构也是一个对象。在函数对象»http://www.cnblogs.com/vamei/archive/2012/07/10/2582772.html✔ 中,我们像使用一个普通对象一样使用函数对象,比如更改函数对象的名字,或者将函数对象作为参数进行传递。

函数对象的作用域

和其他对象一样,函数对象也有其存活的范围,也就是函数对象的作用域。函数对象是使用def语句定义的,函数对象的作用域与def所在的层级相同。比如下面代码,我们在line_conf函数的隶属范围内定义的函数line,就只能在line_conf的隶属范围内调用。

def line_conf(): def line(x): return 2*x+1

print(line(5))   # within the scope

line_conf() print(line(5))       # out of the scope

line函数定义了一条直线(y = 2x + 1)。可以看到,在line_conf()中可以调用line函数,而在作用域之外调用line将会有下面的错误:

NameError: name 'line' is not defined

说明这时已经在作用域之外。

同样,如果使用lambda定义函数,那么函数对象的作用域与lambda所在的层级相同。

闭包

函数是一个对象,所以可以作为某个函数的返回结果。

def line_conf(): def line(x): return 2*x+1

return line       # return a function object my_line = line_conf() print(my_line(5))

上面的代码可以成功运行。line_conf的返回结果被赋给line对象。上面的代码将打印11。

如果line()的定义中引用了外部的变量,会发生什么呢?

def line_conf(): b = 15

def line(x): return 2*x+b return line       # return a function object

b = 5 my_line = line_conf() print(my_line(5))

我们可以看到,line定义的隶属程序块中引用了高层级的变量b,但b信息存在于line的定义之外 (b的定义并不在line的隶属程序块中)。我们称b为line的环境变量。事实上,line作为line_conf的返回值时,line中已经包括b的取值(尽管b并不隶属于line)。

上面的代码将打印25,也就是说,line所参照的b值是函数对象定义时可供参考的b值,而不是使用时的b值。

一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的__closure__属性中。比如下面的代码:

def line_conf(): b = 15

def line(x): return 2*x+b return line       # return a function object

b = 5 my_line = line_conf() print(my_line.__closure__) print(my_line.__closure__[0].cell_contents)

__closure__里包含了一个元组(tuple)。这个元组中的每个元素是cell类型的对象。我们看到第一个cell包含的就是整数15,也就是我们创建闭包时的环境变量b的取值。

下面看一个闭包的实际例子:

def line_conf(a, b): def line(x): return a*x + b return line line1 = line_conf(1, 1) line2 = line_conf(4, 5) print(line1(5), line2(5))

这个例子中,函数line与环境变量a,b构成闭包。在创建闭包的时候,我们通过line_conf的参数a,b说明了这两个环境变量的取值,这样,我们就确定了函数的最终形式(y = x + 1和y = 4x + 5)。我们只需要变换参数a,b,就可以获得不同的直线表达函数。由此,我们可以看到,闭包也具有提高代码可复用性的作用。

如果没有闭包,我们需要每次创建直线函数的时候同时说明a,b,x。这样,我们就需要更多的参数传递,也减少了代码的可移植性。利用闭包,我们实际上创建了泛函。line函数定义一种广泛意义的函数。这个函数的一些方面已经确定(必须是直线),但另一些方面(比如a和b参数待定)。随后,我们根据line_conf传递来的参数,通过闭包的形式,将最终函数确定下来。

闭包与并行运算

闭包有效的减少了函数所需定义的参数数目。这对于并行运算来说有重要的意义。在并行运算的环境下,我们可以让每台电脑负责一个函数,然后将一台电脑的输出和下一台电脑的输入串联起来。最终,我们像流水线一样工作,从串联的电脑集群一端输入数据,从另一端输出数据。这样的情境最适合只有一个参数输入的函数。闭包就可以实现这一目的。

并行运算正称为一个热点。这也是函数式编程又热起来的一个重要原因。函数式编程早在1950年代就已经存在,但应用并不广泛。然而,我们上面描述的流水线式的工作并行集群过程,正适合函数式编程。由于函数式编程这一天然优势,越来越多的语言也开始加入对函数式编程范式的支持。

欢迎继续阅读“Python快速教程»http://www.cnblogs.com/vamei/archive/2012/09/13/2682778.html✔”

小奋斗文章

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434628.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

直接打印报表

在ax中有时可能需要在打印时,不显示报表的预览与设置窗口,而是直接Send到打印机。可以使用ClassFactory、PrintJobSettings、ReportRun来完成。 static void NJ_MF_DirectPrint(Args _args) { Args args new Args(); ReportRun …

如何构建自己的SIP SERVER!

如果你下载了 sip phone, 自己又做了一个 SIP SERVER,那么你就可以当老大了,不要什么MSN,QQ的语音通话了,自己就可以直接同你想要的人通话了。1:软件准备:A: SIP SERVER http://www.brekeke.com/en/download/idx_sipse…

java java.lang_Java之java.lang.IllegalMonitorStateException

今天又中彩了, 原本很简单的多线程程序, 蓦然间冒了个"java.lang.IllegalMonitorStateException" , 杀了个措手不及. 一直纳闷, 为什么为什么? 查资料说该异常由于对象未获取得到Lock就试图操作Lock. 再细细源码, 原来不不小将lock.lock()写错为lock.tryLock(). 坑爹…

CruiseControl.NET ----- mail 配置

最近在用 CruiseControl.NET实现每日构建,其他配置起来都挺方便,就是在邮件设置上费了不少时间,我用的是CC.NET1.6,这个版本已经支持发送附件,如果使用外部邮箱,记得要把邮箱的smtp功能打开,下面是Mail配置的一个例子&…

java编程字_Java编程基本概念

1.标识符①用于给变量、类和方法命名(类名首字母大写,变量和方法名首字母小写并遵循驼峰原则)②标识符的命名规范:■标识符必须以字母、下划线和美元符$开头。■标识符其他部分可以是字母、下划线、美元符和数字的任意组合。■Java标识符大小写敏感&…

ubuntu gedit出错:Failed to connect to the session manager

刚才用su到root后,用命令gedit发现会出错:** (gedit:2976): WARNING **: 连接已关闭(gedit:2976): EggSMClient-WARNING **: Failed to connect to the session manager:None of the authentication protocols specified are supported** (gedit:2976): …

php 类的实现 完整例子

文件目录&#xff1a; --index.php --php --data_info.php index.php 这里要require_once类所在的php文件 <?php require_once(./php/data_info.php);$oneDatanew user;$oneData->setName("username");$oneData->setPassword("password");echo $…

mac java版本 不一致_mac实现不同版本的jdk切换

之前使用jdk11进行java开发(纯粹因为喜欢新版?)但是使用jdk11在布署hadoop伪分布时各种报错, 所以还是下载jdk8回来.接下来就是mac端切换两个版本的jdk(按照网上找的方式好像有bug-文章最后再说.虽然不知道怎么解决,但是至少我可以成功部署hadoop, 所以这里就先忽略)首先下载j…

Meld安装

Ubuntu下文件/目录对比的软件Meld可能有很多用户还不是很熟悉&#xff0c;下文就给大家介绍如何安装Meld和移植到Gedit下。具体内容如下所述。 Meld允许用户查看文件、目录间的变化。很容易移植到Gedit下&#xff0c;方便用户使用。 安装Meld Meld默认在Ubuntu官方源中&#…

ios sqlite3 初级应用

ios sqlite3 初级应用 在ios中&#xff0c;持久化用好几种 方法&#xff0c;前面已经介绍了 两种 &#xff0c;一个是简单的写入文件&#xff0c;另一个是加入了序列化并写入文件中&#xff0c;现在介绍 ios 中嵌入式数据库sqlite3的初级应用 当然在使用sqlite3之前 你需要将l…

java aqs源码_java中AQS源码分析

AQS内部采用CLH队列。CLH队列是由节点组成。内部的Node节点包含的状态有static final int CANCELLED 1;static final int SIGNAL -1;static final int CONDITION -2;static final int PROPAGATE -3;其中取消状态表示任务的取消&#xff0c;SIGNAL状态表示后续节点需要唤…

android4.0.3去掉底部状态栏statusbar,全屏显示示例代码

要去掉android4.0上的状态栏&#xff0c;全屏显示的代码如下&#xff1a; 1、将usleep和killall这二个文件放到assets文件夹下。这二个文件可在下面的附件中下载到。 2、创建Device.java&#xff08;注&#xff1a;附件里有完整的代码&#xff09;: 001import java.io.Buf…

[译]预留位置队列PRQueue:多线程程序中消息输入队列和消息输出队列保持同序...

译自&#xff1a; http://accu.org/var/uploads/journals/overload101.pdf 在多线程应用程序中&#xff0c;要求消息输入队列和消息输出队列顺序要求保持一致&#xff0c;而忽略多线程并发处理的顺序&#xff0c;这种情况是比较难处理的。在本文中&#xff0c;作者设计了一种新…

java 前端工作内容_java前端、java后端、java全栈工作主要内容是什么?哪个薪资高?...

摘要最近&#xff0c;听了一场关于java全栈工程师职位的简介说明&#xff0c;里面很清楚的说明了一下前端&#xff0c;后端&#xff0c;全栈都是做什么工作的。其实&#xff0c;想做这个行业&#xff0c;就应该了解职能以及技能需求&#xff0c;这样学习才能更高效。我知道一些…

用yate2实现软VoIP语音通话(SIP协议)

用yate2实现软VoIP语音通话(SIP协议) 阳光男孩 发表于 2009-01-08 2009年1月7日&#xff0c;工业与信息化部发放了三张3G牌照&#xff0c;标志着中国进入了通信技术的新时代。3G的重要特性之一是高速数据链路&#xff0c;移动上网速度大大提高。同时&#xff0c;中国移动也大…

避免頁面重復提交3/15

在用戶做資料錄入操作時時常會反映重復記錄出現,經過了解是針對新手或者性子急的用戶在儲存時多次點擊引起 有效處理方法:新增一textbox,對儲存按鈕的onclick增設js代碼:btnsave.Attributes.Add("onclick", "var tb15document.getElementById(Textbox15);var nu…

java 日志设计_Java日志设计实践(3) - 开发篇

1.选择恰当的日志级别2.输出明确的提示文字和充分的现场信息3.输出内容一行搞定&#xff0c;不要换行4.其他1.选择恰当的日志级别选择日志级别时需要遵循一些通用规范&#xff0c;不可随意定义log4j的日志级别&#xff0c;由低到高排列&#xff1a;all trace debug info warn e…

ConfigurationManager.AppSettings[] ConfigurationManager智能显示不出来

解决办法&#xff1a;在项目中添加System.Configuration引用。转载于:https://www.cnblogs.com/2008freestyle/archive/2012/03/15/2398046.html

java5的递归算法_java递归算法 java面试题(5)

Java语言是一种具有动态性的解释型语言&#xff0c;类(class)只有被加载到JVM后才能运行。当运行指定程序时&#xff0c;JVM会将编译生成的.class文件按照需求和一定的规则加载到内存中&#xff0c;并组织成为一个完整的Java应用程序。这个加载过程是由类加载器完成&#xff0c…

OpenGL ES 2.0 for iPhone Tutorial

来源&#xff1a;http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial If youre new here, you may want to subscribe to my RSS feed or follow me on Twitter. Thanks for visiting! Learn how to use OpenGL ES 2.0 from the ground up! OpenGL ES is th…