Python自学笔记之函数式编程5——返回函数

函数作为返回值

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

要实现一个可变参数的求和,通常函数是这样定义的:

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

调用函数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()

此例中,每次循环都创建了一个新的函数,然后,把创建的三个函数都返回了。

你可能认为调用f1(),f2(),f3()结果应该是1,4,9,但实际结果是:

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

全部都是9!原因就在于返回的函数引用了变量i,但它并非立刻执行。等到三个函数都返回时,它们所引用的变量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函数缩短代码。

尝试lambda:

def count():
    def f(j):
        return lambda : j*j # 怎么感觉毫无意义呢
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs
时间: 2024-08-10 13:51:13

Python自学笔记之函数式编程5——返回函数的相关文章

Python自学笔记之函数式编程6——匿名函数

我们传入函数时,有时候不需要显式地定义函数,直接传入匿名函数更方便. 在Python中,对匿名函数提供了有限支持.以map()函数为例,计算f(x) = x * x时,除了定义一个f(x)的函数外,还可以直接传入匿名函数: >>> list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])) [1, 4, 9, 16, 25, 36, 49, 64, 81] 通过对比可以看出,匿名函数lambda x: x * x实际上就是: def f

python学习笔记011——函数式编程

1 函数式编程 面向对象 ,面向过程 ,函数式编程 侧重函数的作用,注重函数结果的传递 函数可以被赋值,也可以接受其他的值 2 函数式编程特点 1.函数是一等公民 与其他变量一样,可以赋值和被赋值,可以作为参数传递 2.只用表达式不用语句 表达式是一个单纯的运算过程,总有返回值,语句是执行某种操作,没有返回值.即每一步运算要单纯,有明确结果. 函数式编程是为运算产生的而不是IO 3. 没有副作用 尽量不使用全局内容也不修改系统变量 4.引用透明 函数运行结果因为参数而发生变化,而不是因为系统的状

Python基础笔记:函数式编程:高阶函数、返回函数、匿名函数、装饰器、偏函数

高阶函数 高阶函数:一个函数可以接收另一个函数作为参数 或 一个函数可以返回一个函数作为返回值,这种函数称之为高阶函数. #函数 add 接收 f 函数作为参数 >>> def add(x,y,f): ... return f(x)+f(y) ... >>> add(-5,6,abs) 11 可以把匿名函数作为返回值返回 #把匿名函数作为返回值返回 def build(x, y): return lambda: x * x + y * y 匿名函数 关键字 lambda

Python学习笔记五函数式编程(一)

参考教程:廖雪峰官网https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000 函数式编程 一.高阶函数 所谓高阶函数就是函数可以以另外一个函数作为参数. 首先需要了解在Python中变量是可以指向函数的,如下例子: >>> abs(-5) 5 >>> f=abs >>> f <built-in function abs> >&

python学习笔记(四) - 函数式编程

一. 高阶函数 高阶函数:把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式 def add(x, y, f): return f(x) + f(y) print add(-5, 6, abs) # 11 二.返回函数 aaa 三.匿名函数 aaa 四.装饰器 aaa 五.偏函数 aaa

Python 函数式编程(2) —— 返回函数

Python的函数不但可以返回int.str.list.dict等数据类型,还可以返回函数!例一. 求和[1, 2, 3, 4]def calc_sum(lst):    def calc_sum():        return sum(lst)    return calc_sum f = calc_sum([1, 2, 3, 4])print(f())例二. 请编写一个函数calc_prod(lst),它接收一个list,返回一个函数,返回函数可以计算参数的乘积.from functool

Python学习笔记五函数式编程(二)

参考教程:廖雪峰官网https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000 一.返回函数 高阶函数除了可以接受函数作为参数之外,还可以把函数作为返回值. 通常我们也可以通过以下方式求和: def calc_sum(*args): sum=0 for n in args: sum=sum+n return sum 但如果有一种情况 ,不需要立刻得出求和结果,而是在后续的代码中根据需要再计

python自学笔记

python自学笔记 python自学笔记 1.输出 2.输入 3.零碎 4.数据结构 4.1 list 类比于java中的数组 4.2 tuple 元祖 5.条件判断和循环 5.1 条件判断 5.2 循环 6.使用dict和set 6.1 dict 6.2 set 7.函数的使用 7.1函数返回多个值,同时接受多个值 7.2函数参数的默认值 7.3可变参数的函数 7.4可变个数带参数名的入参 7.5参数类型组合 8.关于函数递归 9.python的高级特性 9.1切片 9.2遍历 9.3列表生

PYTHON修饰器的函数式编程

转自:http://coolshell.cn/articles/11265.html Python修饰器的函数式编程 Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都很相似--都是想要对一个已有的模块做一些"修饰工作",所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能