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和C++求解方法
Aug 20 Python
python机器学习理论与实战(二)决策树
Jan 19 Python
python向已存在的excel中新增表,不覆盖原数据的实例
May 02 Python
Python爬虫实现全国失信被执行人名单查询功能示例
May 03 Python
详解python 注释、变量、类型
Aug 10 Python
pandas 数据结构之Series的使用方法
Jun 21 Python
Python转换时间的图文方法
Jul 01 Python
解决使用export_graphviz可视化树报错的问题
Aug 09 Python
Python 导入文件过程图解
Oct 15 Python
Python+numpy实现矩阵的行列扩展方式
Nov 29 Python
python实现滑雪者小游戏
Feb 22 Python
python之json文件转xml文件案例讲解
Aug 07 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
PHP删除特定数组内容并且重建数组索引的方法.
2011/03/25 PHP
php分页函数完整实例代码
2014/09/22 PHP
php的curl封装类用法实例
2014/11/07 PHP
php ajax实现文件上传进度条
2016/03/29 PHP
Javascript MD4
2006/12/20 Javascript
javascript图像处理—仿射变换深度理解
2013/01/16 Javascript
JavaScript中实现依赖注入的思路分享
2015/01/15 Javascript
JavaScript如何动态创建table表格
2020/08/02 Javascript
前端jquery部分很精彩
2016/05/03 Javascript
jQuery选择器之表单元素选择器详解
2017/09/19 jQuery
AngularJs 禁止模板缓存的方法
2017/11/28 Javascript
浅谈React中组件间抽象
2018/01/27 Javascript
JavaScript中使用import 和require打包后实现原理分析
2018/03/07 Javascript
ionic2.0双击返回键退出应用
2019/09/17 Javascript
使用vue实现HTML页面生成图片的方法
2020/03/12 Javascript
jQuery 隐藏/显示效果函数用法实例分析
2020/05/20 jQuery
js轮播图之旋转木马效果
2020/10/13 Javascript
Python脚本在Appium库上对移动应用实现自动化测试
2015/04/17 Python
八大排序算法的Python实现
2021/01/28 Python
Python中使用asyncio 封装文件读写
2016/09/11 Python
Python编程实现生成特定范围内不重复多个随机数的2种方法
2017/04/14 Python
Python Xml文件添加字节属性的方法
2018/03/31 Python
计算机二级python学习教程(2) python语言基本语法元素
2019/05/16 Python
Pyinstaller 打包exe教程及问题解决
2019/08/16 Python
python3-flask-3将信息写入日志的实操方法
2019/11/12 Python
python 中的命名空间,你真的了解吗?
2020/08/19 Python
荷兰美妆护肤品海淘网站:Beautinow(中文)
2020/11/22 全球购物
介绍一下gcc特性
2012/01/20 面试题
幼儿园家长会欢迎词
2014/01/09 职场文书
公司庆典活动邀请函
2014/01/09 职场文书
《长城》教学反思
2014/02/14 职场文书
无偿献血倡议书
2014/04/14 职场文书
副总经理党的群众路线教育实践活动个人对照检查材料思想汇报
2014/10/06 职场文书
党的群众路线教育实践活动对照检查剖析材料
2014/10/09 职场文书
区域销售经理岗位职责
2015/04/02 职场文书
小学生必读成语故事大全:送给暑假的你们
2019/07/09 职场文书