Python中用函数作为返回值和实现闭包的教程


Posted in Python onApril 27, 2015

函数作为返回值

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

我们来实现一个可变参数的求和。通常情况下,求和的函数是这样定义的:

def calc_sum(*args):
  ax = 0
  for n in args:
    ax = ax + n
  return ax

但是,如果不需要立刻求和,而是在后面的代码中,根据需要再计算怎么办?可以不返回求和的结果,而是返回求和的函数!

def lazy_sum(*args):
  def sum():
    ax = 0
    for n in args:
      ax = ax + n
    return ax
  return sum

当我们调用lazy_sum()时,返回的并不是求和结果,而是求和函数:

>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function sum at 0x10452f668>

调用函数f时,才真正计算求和的结果:

>>> f()
25

在这个例子中,我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

请再注意一点,当我们调用lazy_sum()时,每次调用都会返回一个新的函数,即使传入相同的参数:

>>> f1 = lazy_sum(1, 3, 5, 7, 9)
>>> f2 = lazy_sum(1, 3, 5, 7, 9)
>>> f1==f2
False

f1()和f2()的调用结果互不影响。
闭包

注意到返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用,所以,闭包用起来简单,实现起来可不容易。

另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。我们来看一个例子:

def count():
  fs = []
  for i in range(1, 4):
    def f():
       return i*i
    fs.append(f)
  return fs

f1, f2, f3 = count()

在上面的例子中,每次循环,都创建了一个新的函数,然后,把创建的3个函数都返回了。

你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果是:

>>> f1()
9
>>> f2()
9
>>> f3()
9

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到3个函数都返回时,它们所引用的变量i已经变成了3,因此最终结果为9。

返回闭包时牢记的一点就是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。

如果一定要引用循环变量怎么办?方法是再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变:

>>> def count():
...   fs = []
...   for i in range(1, 4):
...     def f(j):
...       def g():
...         return j*j
...       return g
...     fs.append(f(i))
...   return fs
... 
>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

缺点是代码较长,可利用lambda函数缩短代码。

Python 相关文章推荐
Python和GO语言实现的消息摘要算法示例
Mar 10 Python
Python中列表、字典、元组数据结构的简单学习笔记
Mar 20 Python
python实现用户登录系统
May 21 Python
python中logging包的使用总结
Feb 28 Python
python selenium 对浏览器标签页进行关闭和切换的方法
May 21 Python
django.db.utils.ProgrammingError: (1146, u“Table‘’ doesn’t exist”)问题的解决
Jul 13 Python
python仿evething的文件搜索器实例代码
May 13 Python
python中for循环把字符串或者字典添加到列表的方法
Jul 20 Python
python实现局域网内实时通信代码
Dec 22 Python
基于Tensorflow高阶读写教程
Feb 10 Python
Python实现病毒仿真器的方法示例(附demo)
Feb 19 Python
python画图常规设置方式
Mar 05 Python
Python中利用sorted()函数排序的简单教程
Apr 27 #Python
Python中的filter()函数的用法
Apr 27 #Python
Python中的map()函数和reduce()函数的用法
Apr 27 #Python
PyMongo安装使用笔记
Apr 27 #Python
Windows下PyMongo下载及安装教程
Apr 27 #Python
Python操作MongoDB数据库PyMongo库使用方法
Apr 27 #Python
Python的函数的一些高阶特性
Apr 27 #Python
You might like
Sony CFR 320 修复改造
2020/03/14 无线电
把从SQL中取出的数据转化成XMl格式
2006/10/09 PHP
PHP基础学习之流程控制的实现分析
2013/04/28 PHP
ThinkPHP缓存方法S()概述
2014/06/13 PHP
destoon安全设置中需要设置可写权限的目录及文件
2014/06/21 PHP
初识php MVC
2014/09/10 PHP
3种php生成唯一id的方法
2015/11/23 PHP
Yii框架防止sql注入,xss攻击与csrf攻击的方法
2016/10/18 PHP
你所要知道JS(DHTML)中的一些技巧
2007/01/09 Javascript
jquery 1.3.2 IE8中的一点点的小问题解决方法
2009/07/10 Javascript
jQuery实用函数用法总结
2014/08/29 Javascript
jQuery+jRange实现滑动选取数值范围特效
2015/03/14 Javascript
jQuery处理图片加载失败的常用方法
2015/06/08 Javascript
JavaScript学习笔记之DOM基础 2.4
2015/08/14 Javascript
JavaScript+html5 canvas制作的圆中圆效果实例
2016/01/27 Javascript
Kindeditor在线文本编辑器如何过滤HTML
2016/04/14 Javascript
jQuery选择器实例应用
2017/01/05 Javascript
angularjs的单选框+ng-repeat的实现方法
2018/09/12 Javascript
9102了,你还不会移动端真机调试吗
2019/03/25 Javascript
微信小程序 动态修改页面数据及参数传递过程详解
2019/09/27 Javascript
CentOS 8.2服务器上安装最新版Node.js的方法
2020/12/16 Javascript
[46:43]DOTA2上海特级锦标赛D组小组赛#1 EG VS COL第三局
2016/02/28 DOTA
Python版的文曲星猜数字游戏代码
2013/09/02 Python
Python中的is和id用法分析
2015/01/26 Python
Python实现字典的遍历与排序功能示例
2017/12/23 Python
浅析PEP572: 海象运算符
2019/10/15 Python
Python编程快速上手——正则表达式查找功能案例分析
2020/02/28 Python
利用4行Python代码监测每一行程序的运行时间和空间消耗
2020/04/22 Python
详解pandas.DataFrame.plot() 画图函数
2020/06/14 Python
8款精美的CSS3表单设计(登录表单/下拉选择/按钮附演示及源码)
2013/02/04 HTML / CSS
竞聘医务工作人员的自我评价分享
2013/11/04 职场文书
电子商务专业个人的自我评价
2013/11/19 职场文书
收银员岗位职责
2014/02/07 职场文书
社区活动总结报告
2014/05/05 职场文书
委托培训协议书
2014/11/17 职场文书
Python机器学习应用之基于线性判别模型的分类篇详解
2022/01/18 Python