函数作为返回值

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

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

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. three arrays

    three arrays 字典树上贪心 #include<bits/stdc++.h> using namespace std; ][][]; ][]; ]; ]; ][]; ][]; i ...

  2. 网页分页page

    public class PageBean { private int page; // 第几页 private int pageSize; // 每页记录数 private int start; / ...

  3. elasticsearch堆内存的配置建议

    1.将最小堆大小(Xms)和最大堆大小(Xmx)设置为彼此相等 防止内存抖动 2:给多大的堆内存? 给ES的内存配置不是越大越好,建议不能超过32GB,不同jdk版本最大边界值是不同的,对于32位小于 ...

  4. [CSP-S模拟测试]:购物(柯朵莉树)

    题目描述 $visit_world$有一个商店,商店里卖$N$个商品,第$i$个的价格为$a[i]$我们称一个正整数$K$是美妙的,当且仅当我们可以在商店里选购若干个商品,使得价格之和落在区间$[K, ...

  5. [CSP-S模拟测试]:幻魔皇(数学)

    题目描述 幻魔皇拉比艾尔很喜欢斐波那契树,他想找到神奇的节点对. 所谓斐波那契树,根是一个白色节点,每个白色节点都有一个黑色节点儿子,而每个黑色节点则有一个白色和一个黑色节点儿子.神奇的节点对则是指白 ...

  6. qbzt day4 下午

    有向图的强连通分量 强联通:两个点之间可以互相到达 如果某个图任意两个点都是强联通的,那么称这个图强联通 如果一个图的子图是强联通的,那么称这个图是强联通子图 一个图的极大强联通子图被称作强连通分量 ...

  7. Redis 简介,安装,卸载

    一.Redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(s ...

  8. python-网络编程urllib模块

    一.操作网络发送请求 from urllib.request import urlopen   #发送请求 from urllib.parse import urlencode   #用来把字典形式转 ...

  9. charles之抓取浏览器https请求

    用charles抓取浏览器https的包时,请求显示为unknown,且请求和响应数据乱码,本篇介绍如何抓取正常响应的https请求 目录 1.安装charles 2.安装证书.添加域名 3.抓包 1 ...

  10. python中有哪些类型的布尔值是False?

    1.None 2. False 3.所有的值为零的数 4."" 5.[] 6.() 7.{}