zoukankan      html  css  js  c++  java
  • python_闭包_匿名函数

    闭包

    在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问:

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

    g 的定义移入函数 f 内部,防止其他代码调用 g

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

    但是,考察上一小节定义的 calc_sum 函数:

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

    注意: 发现没法把 lazy_sum 移到 calc_sum 的外部,因为它引用了 calc_sum 的参数 lst

    像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(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()

    你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9(请自己动手验证)。

    原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时:

    >>> f1()
    9     # 因为f1现在才计算i*i,但现在i的值已经变为3

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

    任务

    返回闭包不能引用循环变量,请改写count()函数,让它正确返回能计算1x1、2x2、3x3的函数。

     

    考察下面的函数 f:

    def f(j):
        def g():
            return j*j
        return g

    它可以正确地返回一个闭包g,g所引用的变量j不是循环变量,因此将正常执行。

    在count函数的循环内部,如果借助f函数,就可以避免引用循环变量i。

    参考代码:

    def count():
        fs = []
        for i in range(1, 4):
            def f(j):
                def g():
                    return j*j
                return g
            r = f(i)
            fs.append(r)
        return fs
    f1, f2, f3 = count()
    print f1(), f2(), f3()


    匿名函数

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

    在Python中,对匿名函数提供了有限支持。还是以map()函数为例,计算 f(x)=x时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:

    >>> 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(x):
        return x * x

    关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数。

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

    使用匿名函数,可以不必定义函数名,直接创建一个函数对象,很多时候可以简化代码:

    >>> sorted([1, 3, 9, 5, 0], lambda x,y: -cmp(x,y))
    [9, 5, 3, 1, 0]

    返回函数的时候,也可以返回匿名函数:

    >>> myabs = lambda x: -x if x < 0 else x 
    >>> myabs(-1)
    1
    >>> myabs(1)
    1

    任务

    利用匿名函数简化以下代码:

    def is_not_empty(s):
        return s and len(s.strip()) > 0
    filter(is_not_empty, ['test', None, '', 'str', '  ', 'END'])
    ?不会了怎么办

    定义匿名函数时,没有return关键字,且表达式的值就是函数返回值。

    参考代码:

    print filter(lambda s: s and len(s.strip())>0, ['test', None, '', 'str', '  ', 'END'])
  • 相关阅读:
    670. Maximum Swap
    653. Two Sum IV
    639. Decode Ways II
    636. Exclusive Time of Functions
    621. Task Scheduler
    572. Subtree of Another Tree
    554. Brick Wall
    543. Diameter of Binary Tree
    535. Encode and Decode TinyURL
    博客园自定义背景图片
  • 原文地址:https://www.cnblogs.com/hi-23/p/4330715.html
Copyright © 2011-2022 走看看