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实现通过微信搜索功能查看谁把你删除了
Jan 27 Python
python框架django基础指南
Sep 08 Python
python实现协同过滤推荐算法完整代码示例
Dec 15 Python
Python2包含中文报错的解决方法
Jul 09 Python
python 实现对数据集的归一化的方法(0-1之间)
Jul 17 Python
使用Python正则表达式操作文本数据的方法
May 14 Python
基于python实现微信好友数据分析(简单)
Feb 16 Python
在python中使用pymysql往mysql数据库中插入(insert)数据实例
Mar 02 Python
使用jupyter Nodebook查看函数或方法的参数以及使用情况
Apr 14 Python
python中对二维列表中一维列表的调用方法
Jun 07 Python
Python3.9 beta2版本发布了,看看这7个新的PEP都是什么
Jun 10 Python
Django ModelForm组件原理及用法详解
Oct 12 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中运用http调用的GET和POST方法示例
2014/09/29 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
Laravel5.4简单实现app接口Api Token认证方法
2019/08/29 PHP
javascript 主动派发事件总结
2011/08/09 Javascript
jQuery打印图片pdf、txt示例代码
2014/07/22 Javascript
使用jQuery简单实现模拟浏览器搜索功能
2014/12/21 Javascript
JavaScript实现16进制颜色值转RGB的方法
2015/02/09 Javascript
jQuery简单几行代码实现tab切换
2015/03/10 Javascript
js实现三张图(文)片一起切换的banner焦点图
2015/08/25 Javascript
jQuery解决IE6、7、8不能使用 JSON.stringify 函数的问题
2016/05/31 Javascript
JavaScript中两个字符串的匹配
2016/06/08 Javascript
jQuery 常见小例汇总
2016/12/14 Javascript
JS 在数组指定位置插入/删除数据的方法
2017/01/12 Javascript
AngularJS入门教程一:路由用法初探
2017/05/27 Javascript
Angular2环境搭建具体操作步骤(推荐)
2017/08/04 Javascript
elementUI Vue 单个按钮显示和隐藏的变换功能(两种方法)
2018/09/04 Javascript
nodeJs项目在阿里云的简单部署
2020/11/27 NodeJs
[02:28]PWL开团时刻DAY3——Ink Ice与DeMonsTer之间的勾心斗角
2020/11/03 DOTA
[42:32]完美世界DOTA2联赛PWL S2 LBZS vs FTD.C 第二场 11.27
2020/12/01 DOTA
利用Python如何生成随机密码
2016/04/20 Python
python实现数据图表
2017/07/29 Python
深入理解Python3 内置函数大全
2017/11/23 Python
python绘制立方体的方法
2018/07/02 Python
浅谈pytorch和Numpy的区别以及相互转换方法
2018/07/26 Python
利用python开发app实战的方法
2019/07/09 Python
Pycharm及python安装详细步骤及PyCharm配置整理(推荐)
2020/07/31 Python
python argparse模块通过后台传递参数实例
2020/04/20 Python
CSS Houdini实现动态波浪纹效果
2019/07/30 HTML / CSS
俄语专业毕业生推荐信
2013/10/28 职场文书
大学生社会实践评语
2014/04/25 职场文书
工商干部先进事迹
2014/05/14 职场文书
教师节标语大全
2014/10/07 职场文书
作文评语集锦
2014/12/25 职场文书
学生上课迟到检讨书
2015/01/01 职场文书
2015年支教教师工作总结
2015/07/22 职场文书
Redis Lua脚本实现ip限流示例
2022/07/15 Redis