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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值