返回函数


函数作为返回值

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

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

>>> def a(*args):
ax=
for n in args:
ax =ax+n
return ax >>> a([,,])
Traceback (most recent call last):
File "<pyshell#6>", line , in <module>
a([,,])
File "<pyshell#5>", line , in a
ax =ax+n
TypeError: unsupported operand type(s) for +: 'int' and 'list'
>>> a(,,,)

这里不能用list传参 注意是*args

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

>>> def a(*args):
def sum():
ax=
for n in args:
ax=ax+n
return ax
return sum

当我们调用a()时,返回的并不是求和结果,而是求和函数:调用函数s时,才真正计算求和的结果:

>>> s=a(,)
>>> s
<function a.<locals>.sum at 0x05D14C00>
>>> s()

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

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

>>> s1=a(1,2)
>>> s2=a(1,2)
>>> s1==s2
False

s1()和s2()的调用结果互不影响。

闭包

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

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

>>> def p():
fs=[]
for i in range(,):
def f():
return i*i
fs.append(f)
return fs >>> f1,f2,f3 =count()
Traceback (most recent call last):
File "<pyshell#39>", line , in <module>
f1,f2,f3 =count()
NameError: name 'count' is not defined
>>> f1,f2,f3 =p()
>>> f1() >>> f2() >>> f3()

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

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

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

>>> def count():
fs=[]
for i in range(,):
def f(j):
def g():
return j*j
return g
fs.append(f(i))
return fs >>> f1=count()
>>> f1()
Traceback (most recent call last):
File "<pyshell#33>", line , in <module>
f1()
TypeError: 'list' object is not callable
>>> f1, f2, f3 = count()
SyntaxError: unexpected indent
>>> f1, f2, f3 = count()
>>> f1() >>> f2() >>> f3()
对于@塔塔gogo的例子,说白了就是i是公共的,j是私有的。也就是
i=1
j=i #f1可使用这个j,以及公共的i
i=2
j=i #f2可使用这个j,以及公共的i
i=3
j=i #f3可使用这个j,以及公共的i

虽然表面上看有3个j,然而这3个j在内存中具有不同的地址,而公共的i只有一个地址。

最后计算f1()时,虽然此时i=3,但是f1中的j为1,从而得到结果1;同理f2()为4,f3()为9.

下面将这个程序稍作修改,结果显而易见。

count()中存放的是三个f函数,当调用f1,f2,f3 = count()时,此时的for循环结束了,i=3.再执行f1()的时候相当于执行下面: i=3 def f(): return i*i 这个时候的值为9.

其实count()执行后,是返回一个这样的list【g(j1),g(j2),g(j3)】,而不是【f(j1),f(j2),f(j3)】。然后>>> f1, f2, f3 = count()分别指向list中的每个元素。

lambda简化函数

f1, f2, f3 = map(lambda y : (lambda : y * y), range(1,4))

python学习之路(18)的更多相关文章

  1. Python学习之路【第一篇】-Python简介和基础入门

    1.Python简介 1.1 Python是什么 相信混迹IT界的很多朋友都知道,Python是近年来最火的一个热点,没有之一.从性质上来讲它和我们熟知的C.java.php等没有什么本质的区别,也是 ...

  2. python学习之路-day2-pyth基础2

    一.        模块初识 Python的强大之处在于他有非常丰富和强大的标准库和第三方库,第三方库存放位置:site-packages sys模块简介 导入模块 import sys 3 sys模 ...

  3. Python学习之路-Day2-Python基础3

    Python学习之路第三天 学习内容: 1.文件操作 2.字符转编码操作 3.函数介绍 4.递归 5.函数式编程 1.文件操作 打印到屏幕 最简单的输出方法是用print语句,你可以给它传递零个或多个 ...

  4. Python学习之路-Day2-Python基础2

    Python学习之路第二天 学习内容: 1.模块初识 2.pyc是什么 3.python数据类型 4.数据运算 5.bytes/str之别 6.列表 7.元组 8.字典 9.字符串常用操作 1.模块初 ...

  5. Python学习之路-Day1-Python基础

    学习python的过程: 在茫茫的编程语言中我选择了python,因为感觉python很强大,能用到很多领域.我自己也学过一些编程语言,比如:C,java,php,html,css等.但是我感觉自己都 ...

  6. python学习之路网络编程篇(第四篇)

    python学习之路网络编程篇(第四篇) 内容待补充

  7. python 学习之路开始了

    python 学习之路开始了.....记录点点滴滴....

  8. python学习之路,2018.8.9

    python学习之路,2018.8.9, 学习是一个长期坚持的过程,加油吧,少年!

  9. Python学习之路——pycharm的第一个项目

    Python学习之路——pycharm的第一个项目 简介: 上文中已经介绍如何安装Pycharm已经环境变量的配置.现在软件已经安装成功,现在就开始动手做第一个Python项目.第一个“Hello W ...

  10. python学习之路------你想要的都在这里了

    python学习之路------你想要的都在这里了 (根据自己的学习进度后期不断更新哟!!!) 一.python基础 1.python基础--python基本知识.七大数据类型等 2.python基础 ...

随机推荐

  1. (转载)sublime3安装markdown插件

    原文链接 http://www.jianshu.com/p/335b7d1be39e?utm_source=tuicool&utm_medium=referral 最近升级到了 Sublime ...

  2. 将Abp的UnitTest中的InMemory改为SQLite in memory

    添加nuget包 Microsoft.EntityFrameworkCore.Sqlite 添加ServiceCollectionRegistrarSqlite public static class ...

  3. 098、Swarm 如何实现 Failover (Swarm05)

    参考https://www.cnblogs.com/CloudMan6/p/7898245.html   故障是在所难免的,容器可能崩溃,Docker Host 可能宕机,不过幸运的是,Swarm 已 ...

  4. debezium关于cdc的使用(下)

    博文原址:debezium关于cdc的使用(下) 简介 debezium在debezium关于cdc的使用(上)中有做介绍.具体可以跳到上文查看.本篇主要讲述使用kafka connector方式来同 ...

  5. 帝国cms 遍历某个父栏目下所有的子栏目

    [e:loop={"select * from phome_enewsclass where bclassid in (2) order by classid asc",0,24, ...

  6. python根据已有数据库生成model.py

    有时我们需要根据已存在的数据库进行django开发时,手写model.py是不现实的 先执行下面的语句,在命令行终端会输出所有表的类 python .\manage.py inspectdb 检查无误 ...

  7. 12、rpm

    1.什么是rpm 由红帽开发用于软件包的安装 升级 卸载 查询 2.rpm包是什么样? 组成部分是什么样的? zip-3.0-11.el7.x86_64.rpm #el7 zip-3.0-1. el6 ...

  8. 2.flask模板--jinja2

    1.jinja2模板介绍和查找路径 import os from flask import Flask, render_template # 之前提到过在渲染模板的时候,默认会从项目根目录下的temp ...

  9. vi 纵向模式编辑

    Vim 的纵向编辑模式 vim解读 vi解读 批量删除# 技巧: r 进入修改模式 I 进入行首插入模式 A 进入行尾插入模式 r替换 I前前添加 A后添加 1.多行注释: a. 按下Ctrl + v ...

  10. MXNetError: [05:53:50] src/operator/nn/./cudnn/cudnn_convolution-inl.h:287

    insightface train.py 报错:mxnet.base.MXNetError: [05:53:50] src/operator/nn/./cudnn/cudnn_convolution- ...