Python lambda 与 闭包

来源:互联网 发布:embed js获取播放时间 编辑:程序博客网 时间:2024/06/06 01:27

Lambda

高阶函数可以接收函数做参数,有些时候,我们不需要显式地定义函数,直接传入匿名函数更方便,也就是lambda

先来看个简单 lambda 函数

>>> lambda x, y : x+y<function <lambda> at 0x102bc1c80>

x 和 y 是函数的两个参数,冒号后面的表达式是函数的返回值,你能一眼看出这个函数就是是在求两个变量的和,但作为一个函数,这里我们暂且给这个匿名函数绑定一个名字,这样使得我们调用匿名函数成为可能。

>>> add = lambda x, y : x+y>>> add<function <lambda> at 0x102bc2140>>>> add(1,2)3

它等同于常规函数

>>> def add2(x, y):...     return x+y...>>> add2<function add2 at 0x102bc1c80>>>> add2(1,2)3

匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果。

例如一个整数列表,要求按照列表中元素的绝对值大小升序排列。

>>> list1 = [3,5,-4,-1,0,-2,-6]>>> sorted(list1, key=lambda x: abs(x) , reverse = False)

排序函数 sorted 支持接收一个函数作为参数,该参数作为 sorted 的排序依据,这里按照列表元素的绝对值进行升序排序。当然,我们也可以用普通函数来实现:

>>> def foo(x):...     return abs(x)...>>> sorted(list1, key=foo)

闭包

下面的一段代码定义了两个函数f() 和 g(),在函数f()中把g()作为返回值返回。

这里的g你可以参考C语言中函数的指针来进行理解,它们两个几乎在语义和用法上几乎完全相同。

def g():    print 'g()...'def f():    print 'f()...'    return g

我们把函数g()的定义移到f()内部,这样除了f()之外的区域就无法调用g():

def f():    print 'f()...'    def g():        print 'g()...'    return g

但是对于以下 calc_sum 函数,发现没法把 lazy_sum 移到 calc_sum 的外部,因为它引用了 calc_sum 的参数 lst:

def calc_sum(lst):    def lazy_sum():        return sum(lst)    return lazy_sum

lst是一个列表,作为参数传进函数calc_sum()中。

此时我们发现无法把函数lazy_sum()移到函数calc_sum()的外面,因为函数lazy_sum()的功能是计算list中所有元素值的和,必须依赖于函数calc_sum()的参数。

如果函数lazy_sum()不在函数calc_sum()里面,则无法取得数据进行计算。

像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。

闭包的特点是返回的函数还引用了外层函数的局部变量

所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变,例如:

# 希望一次返回3个函数,分别计算1x1,2x2,3x3:def count():    fs = []    for i in range(1, 4):        def f():             return i*i        fs.append(f)    return fsf1, f2, f3 = count()print(f1(),f2(),f3())

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

因为当count()函数返回三个函数时,这三个变量所引用的变量i的值已经变成了3,因为在返回的时候三个函数并没有被调用。

所以此时它们并没有及时计算它们对应的i乘以i的值,等到三个函数都返回时,然后调用三个函数,此时i的值已经为3,计算i*i的值自然就都是9了。

因此,返回函数不要引用任何循环变量,或者后续会发生变化的变量

将上述程序如下改写后,即可得到结果1,4,9。

def count():    fs = []    for i in range(1, 4):        def f(m=i):            return m*m        fs.append(f)    return fsf1, f2, f3 = count()print (f1(), f2(), f3())
0 0
原创粉丝点击