python进阶-函数式编程库toolz用法介绍-part2

2018-08-24  本文已影响0人  DATA_KENGOU

  在第一部分简单介绍了python的函数式编程基本方法后,从这部分开始将开始更深入的学习toolz的使用方法。话不多说,下面开始上示例代码。
  将上一部分的函数拿来继续用

def add(x, y):
    return x + y

def mul(x, y):
    return x * y

def lesser(x, y):
    if x < y:
        return x
    else:
        return y

def greater(x, y):
    if x > y:
        return x
    else:
        return y

  首先是accumulate的用法,功能类似于numpy的累加,不过操作(加、乘或其他计算)具体由传入的第一个参数来决定;又可以看出和reduce相近,只不过reduce只返回最后的结果

import numpy as np
X[X>=10].cumsum()
# >>>array([ 10,  21,  33,  46,  60,  75,  91, 108, 126, 145], dtype=int32)

data = range(10, 20)
list(accumulate(add, data))
# >>>[10, 21, 33, 46, 60, 75, 91, 108, 126, 145]

from functools import reduce
reduce(add,data)
# >>>145

  继续来看mapreduceaccumulate的更灵活的一些用法,

data1 = [1, 2, 3, 4, 5]
data2 = [10, 20, 30, 40, 50]
list(map(add, data1, data2))
# >>>[11, 22, 33, 44, 55]

reduce(lesser, [5, 3, 2, 7, 3], 999999999) # 注意第三个参数为初值
# >>> 2
reduce(lesser, [5, 3, 2, 7, 3], 1)
# >>> 1

list(accumulate(lesser, [5, 3, 2, 7, 3]))
# >>> [5, 3, 2, 2, 2]

  可以看出mapreduceaccumulate的第一个参数需要传入一个两个参数的函数(类似于双目运算符)。
  到现在为止,热身活动已经结束了,开始介绍下面重要的一个概念,函数的柯里化(Currying,中文翻译还是有些怪,看英文有可能突然想到投3分的库里啊)。首先介绍python中的几种处理高阶函数(higher order function)的方式,高阶函数可以简单理解为函数的函数,即函数可以当做变量传来传去,从而达到更灵活的用法。

#方式1 普通函数
def cumsum(data):
    return accumulate(add, data)
#方式2 匿名函数
cumsum = lambda data: accumulate(add, data)
#方式3 偏函数
from functools import partial
cumsum = partial(accumulate, add)
#三种方式都是下面一个结果
list(cumsum(data))
# >>>[10, 21, 33, 46, 60, 75, 91, 108, 126, 145]

  我们用高阶函数的方式实现了一个输出每步累加值的函数cumsum,除了普通函数的方式外,另外两种方式个人感觉都还算pythonic,选哪种看个人喜好了。
  同样的功能,更函数式的方式,下面轮到神射手curry出场了!

from toolz import curry
mul_cur = curry(mul)
mul_cur(2)  # 传入参数后返回一个函数,然后就剩下一个参数可传了
# >>> <function mul at 0x00000000072A1EA0>
mul_cur(2)(3)
# >>> mul_cur(2)(3)

# 方式4 currying的方式
accumulate = curry(accumulate)
cumsum = accumulate(add)

  用斐波那契函数的例子来说明一下稍微复杂一点的情况,生成斐波那契数列的前10个数字,但是又不想(或者不能)改变fib函数的前提下(虽然我知道这样执行效率低),通过curry来得到了一个新的函数,相比于直接用列表展开或者每次都用map去做的话,肯定是更加方便快捷,并且通过新的函数名提高了程序的可读性。

def fib(n):
    a, b = 0, 1
    for i in range(n):
        a, b = b, a + b
    return b
fib(9)
# >>> 55
map = curry(map)
fibMany = map(fib)
list(fibMany(range(10)))
# >>> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

  最后,告诉大家其实没必要每次都用curry去“包裹”一次maptoolz里面做好准备工作,提供了相关的柯里化好的函数。

from toolz.curried import map, accumulate, reduce, filter  
# 函数很多就不一一列举了, 这些都等价于下面手动柯里化
from toolz import map, curry
map = curry(map)

  未完待续 ...

上一篇下一篇

猜你喜欢

热点阅读