函数作为返回值

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

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

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 lazy_sum.<locals>.sum at 0x101c6ed90>

调用函数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()结果应该是149,但实际结果是:

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

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

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

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

def count():
def f(j):
def g():
return j*j
return g
fs = []
for i in range(1, 4):
fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
return fs

再看看结果:

>>> f1, f2, f3 = count()
>>> f1()
1
>>> f2()
4
>>> f3()
9

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

小结

一个函数可以返回一个计算结果,也可以返回一个函数。

返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

python3-返回函数的更多相关文章

  1. Python3返回函数

    函数作为返回值 高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回. 我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_sum(*args): ax = ...

  2. Python3之返回函数

    参考:https://www.cnblogs.com/mzc1997/p/7641995.html Python中函数不仅可以作为参数还可以作为结果返回 >>> def pro1(c ...

  3. [Python3] 036 函数式编程 返回函数

    目录 函数式编程 之 返回函数 1. 引子 2. 闭包 closure 函数式编程 之 返回函数 函数可以返回具体的值 也可以返回一个函数作为结果 1. 引子 1.1 定义一个普通函数 >> ...

  4. Python3 isinstance() 函数

    Python3 isinstance() 函数 描述 isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type(). isinstance() 与 type() 区别: typ ...

  5. Python3 round() 函数

    Python3 round() 函数  Python3 数字 描述 round() 方法返回浮点数x的四舍五入值. 语法 以下是 round() 方法的语法: round( x [, n] ) 参数 ...

  6. Python3 reversed 函数

    Python3 reversed 函数  Python3 内置函数 描述 reversed 函数返回一个反转的迭代器. 语法 以下是 reversed 的语法: reversed(seq) 参数 se ...

  7. Python3 range() 函数用法

    Python3 range() 函数用法  Python3 内置函数 Python3 range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表. Pyth ...

  8. Python3 chr() 函数

    Python3 chr() 函数 Python3 内置函数 描述 chr() 用一个整数作参数,返回一个对应的字符. 语法 以下是 chr() 方法的语法: chr(i) 参数 i -- 可以是 10 ...

  9. Python3 tuple 函数

    Python3 tuple 函数  Python3 内置函数 描述 tuple 函数将列表转换为元组.. 语法 以下是 tuple 的语法: tuple( seq ) 参数 seq -- 要转换为元组 ...

  10. Python3 bytes 函数

    Python3 bytes 函数  Python3 内置函数 描述 bytes 函数返回一个新的 bytes 对象,该对象是一个 0 <= x < 256 区间内的整数不可变序列.它是 b ...

随机推荐

  1. iptables List the rules in a chain or all chains

    [root@e ~]# iptables -hiptables v1.4.21 Usage: iptables -[ACD] chain rule-specification [options] ip ...

  2. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_09 序列化流_2_对象的序列化流_ObjectOutputStream

    创建person对象.生成构造方法全参和无参.getter和setter 抛出异常:没有序列化异常 接口的源码 啥都没有.就起到一个标记的作用 用二进制存的

  3. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_02 递归_5_综合案例_文件搜索

    复制上一节课的代码 这三种方式都可以获取到文件的名称 把目录的打印注释掉 如果把文件的后缀改成大写的JAVA 再获取就获取不到了 文件名或者路径 转换为小写的字符串 链式编程

  4. 如何在sql server数据库中建立主从表

    建立关联是通过外键引用实现的 例如建立一个学生表和班级表的关联,可以如下: create table class ( classid char(4) primary key not null, cla ...

  5. 04 bbed修复system文件头损坏

    04 bbed修复system文件头损坏 1 启动数据库,查看trace,在mount到open, SQL> startup mount; ORACLE instance started. To ...

  6. 转 linux查看文件前几行和后几行的命令

    可以使用head(查看前几行).tail(查看末尾几行)两个命令.例如:查看/etc/profile的前10行内容,应该是:# head -n 10 /etc/profile查看/etc/profil ...

  7. NornJ-javascript模版引擎

    NornJ-javascript模版引擎 NornJ是一个渲染效率高,语法可读性好,可扩展性超强,适用场景丰富的javascript模板引擎. 学习网址:https://www.npmjs.com/p ...

  8. Jenkins安装配置 远程发布SpringBoot项目

    环境要求: Java : 1.8.0_161. Maven :http://maven.apache.org/download.cgi 3.6.1 下载完解压,配置环境变量:vim /etc/prof ...

  9. squid代理服务问答

    1. 简述一下squid的用途?squid可以做代理和缓存服务器,而做代理时,可以分为正向代理和反向代理.正向代理用在企业办公环境中,企业员工上网通过代理来上网,代理的缓存功能可以为企业节省宝贵的带宽 ...

  10. ESP32、GPRS A9测试

    测试内容: 1.A9作为客户端,在服务器主动断开连接或异常断开的时候,使用网络连接状态查询接口,能否获得准确的网络连接状态. 结果: TCP: A9开多连接时,成功连接TCP服务器后,发送查询语句AT ...