zoukankan      html  css  js  c++  java
  • Python基础:09函数式编程

            Python支持一些函数式编程的特性。比如lambda、 map()、reduce()、filter()函数。

     

    一:匿名函数与lambda

            Python可以用lambda 关键字创造匿名函数。匿名函数不需要以标准的方式来声明(使用def 语句)。作为函数,它们也能有参数。

            一个完整的lambda“语句”代表了一个表达式,这个表达式的定义体必须和声明放在同一行。匿名函数的语法如下:

    lambda [arg1[, arg2, ... argN]]: expression

     

            参数是可选的,lambda 生成一个可以像其他函数一样使用的函数对象。

     

            比如下面的简单函数:

    def true(): return True

            对于该函数,可以使用lambda表达式生成等价的函数对象:

    >>> lambda :True
    <function <lambda> at f09ba0>

            在上面的例子中,只是简单地用lambda创建了一个函数(对象),但是该函数对象创建完之后就被垃圾回收了。

    为了保留住这个对象,将它保存到一个变量中,以后可以随时调用:

    >>> true = lambda :True
    >>> true()
    True

             下面是更多的例子:

    def add(x, y): return x + y  等价于 lambda x, y: x + y

    def usuallyAdd2(x, y=2): return x+y 等价于 lambda x, y=2: x+y

    def showAllAsTuple(*z): return z等价于lambda *z: z

     >>> a = lambda x, y=2: x + y
    >>> a(3)
    5
    
    >>> a(3,5)
    8
    
    >>> a(0)
    2
    
    >>> a(0,9)
    9
    >>> 
    >>> b = lambda *z: z
    >>> b(23, 'zyx')
    (23, 'zyx')
    
    >>> b(42)
    (42,)

      

    二:filter()、map()、reduce()

            这些函数提供了在python 中可以找到的函数式编程的特征。lambda 表达式可以很好的和这些函数相结合,因为这些函数都带了一个可执行的函数对象的参数。lambda 表达式提供了迅速创造这个参数的机制。

     

            a:filter(function, iterable)

            给定一个对象的序列和一个“过滤”函数,每个序列元素都通过这个过滤器进行筛选,保留函数返回为真的的对象。filter 函数为已知的序列的每个元素调用给定布尔函数function。将经过function处理返回True值的元素添加到一个列表中。返回的对象是一个从原始队列中“过滤后”的列表。

            注意:如果iterable是一个字符串或者元组的话,则结果也是同样的类型,否则,结果为一个列表。如果function为None的话,则该函数表现为一个身份函数,也就是该函数会返回,iterable中所有值为True的元素组成的列表。

     

            如果用纯python 编写filter(),它或许就像这样:

    def filter(bool_func, seq):
            filtered_seq= []
            for  eachItem in seq:
                    if bool_func(eachItem):
                            filtered_seq.append(eachItem)
    
            return filtered_seq 

    例子如下:

    >>> alist = [1,2,3,0,4,5]
    >>> filter(None, alist)
    [1, 2, 3, 4, 5]
    
     >>> filter(lambda x: True,'abcdefg')
    'abcdefg'
    
     >>> filter(lambda x: True,(1,2,3,4,5))       
    (1, 2, 3, 4, 5)

             注意,如果function不是None的话,则filter(function,iterable)等价于:[item for item in iterable if function(item)]。如果function为None的话,则它等价于[itemfor item in iterable if item]。比如求一个随机列表中所有奇数的方法:

    allNums = []
    for eachNum in range(9):
            allNums.append(randint(1,99))
    
    print filter(lambda n: n%2, allNums)

     等价于:

    allNums = []
    for eachNum in range(9):
            allNums.append(randint(1,99))
    print [n for n in allNums if n%2]

             b:map(function, iterable, ...)

            将function应用到iterable中的每个元素上,并返回一个由返回值组成的列表。如果给出了多个iterable参数,则function必须具有相同数目的参数,并且该function会并行的迭代所有iterable中的元素。如果其中一个iterable比较短,则假设用None将其扩展。

            如果function为None,则如果给出了多个iterable,那map返回一个元素为元组的列表,其中的元组包含所有iterable的相应元素。

            该函数的结果只能是列表。

     

            如果要用python 编写一个简单的只有一个iterable的map(),代码如下:

    def map(func, seq):
            mapped_seq= []
            for  eachItem in seq:
                    mapped_seq.append(func(eachItem))
            return mapped_seq

    例子如下:

    >>> map((lambda x: x+2), [0, 1, 2, 3, 4, 5])
    [2, 3, 4, 5, 6, 7]
    
    >>> map(None, (1,2,3,4),'abc')
    [(1, 'a'), (2, 'b'), (3, 'c'), (4, None)]
    
    >>> map(lambda x: x**2, range(6))
    [0, 1, 4, 9, 16, 25]
    
     >>> map(lambda x, y: x + y, [1,3,5], [2,4,6])
    [3, 7, 11]
    
    >>> map(lambda x, y: (x+y, x-y), [1,3,5],[2,4,6])
    [(3, -1), (7, -1), (11, -1)]
    
    >>> map(None, [1,3,5], [2,4,6])
    [(1, 2), (3, 4), (5, 6)]

      

            c:reduce(function, iterable[, initializer])

            function是有两个参数的函数,它会持续的对iterable中,从左到右的每个元素进行处理,从而会将iterable中所有元素reduce为一个值。比如reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]),将会计算((((1+2)+3)+4)+5)。左参数x是累计计算的结果,右参数y是iterable中的下一个元素。如果给定initializer参数值的话,则它会是第一个左参数,iterable中的第一个元素是第一个右参数。如果initializer没有给定值,则第一个左参数为iterable[0],第一个右参数为iterable[1]。

            reduce的类Python代码实现如下:

    def reduce(function, iterable, initializer=None):
        it = iter(iterable)
        if initializeris None:
            try:
                initializer= next(it)
            except StopIteration:
                raiseTypeError('reduce() of empty sequence with no initial value')
    
        accum_value =initializer
        for x in it:
            accum_value= function(accum_value, x)
    
        return accum_value

            例子如下;

    >>> print 'the total is:', reduce((lambda x,y:x+y), range(5))
    the total is: 10

     

    三:偏函数

            偏函数类似于默认参数,可以降低函数调用的难度。举例如下:

            int()函数可以把字符串转换为整数,当仅传入字符串时,int()函数默认按十进制转换:

    >>> int('12345')
    12345

            但int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做N进制的转换:

    >>> int('12345', base=8)
    5349
    
    >>> int('12345', 16)
    74565

             假设要转换大量的二进制字符串,每次都传入int(x, base=2)非常麻烦,于是,我们想到,可以定义一个int2()的函数,默认把base=2传进去:

    def int2(x, base=2):
        return  int(x, base)

             这样,我们转换二进制就非常方便了:

    >>> int2('1000000')
    64
    
    >>> int2('1010101')
    85

            functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:

    >>> import functools
    
    >>> int2 = functools.partial(int, base=2)
    >>> int2('1000000')
    64
    
    >>> int2('1010101')
    85

             所以,简单总结functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。

            注意到上面的新的int2函数,仅仅是把base参数重新设定默认值为2,但也可以在函数调用时传入其他值:

    >>> int2('1000000', base=10)
    1000000

            最后,创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数,当传入:int2 = functools.partial(int, base=2)实际上固定了int()函数的关键字参数base,也就是:

    int2('10010')

    相当于:

    kw = { base: 2 }

    int('10010', **kw)

            当传入:

    max2 = functools.partial(max, 10)

            实际上会把10作为*args的一部分自动加到左边,也就是:

    max2(5, 6, 7)

    相当于:

    args = (10, 5, 6, 7)

    max(*args)

    结果为10。

     

    参考:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819893624a7edc0e3e3df4d5d852a352b037c93ec000

  • 相关阅读:
    Centos下安装Redis
    BZOJ 4870 [Shoi2017]组合数问题 ——动态规划 矩阵乘法
    BZOJ 4868 [Shoi2017]期末考试 ——三分 枚举
    BZOJ 4584 [Apio2016]赛艇 ——动态规划
    BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
    BZOJ 2330 [SCOI2011]糖果 ——差分约束系统 SPFA
    Topcoder SRMCards ——贪心
    CTSC 1999 家园 【网络流24题】星际转移
    BZOJ 3489 A simple rmq problem ——KD-Tree
    BZOJ 2733 [HNOI2012]永无乡 ——线段树 并查集
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247207.html
Copyright © 2011-2022 走看看