Python lambda 与 闭包

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 fs

f1, 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 fs

f1, f2, f3 = count()
print (f1(), f2(), f3())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值