详解Python 函数式复合和柯里化

  • Post category:Python

Python 函数式编程为我们提供了很多方便的工具以及技术。

函数式编程的两个概念:函数式复合和柯里化,它们为我们提供了可优雅实现不可变性和高阶函数的能力。

函数式复合

函数式复合是指将多个函数组合起来,形成一个新的函数。函数式编程提供了三个与函数复合相关的函数:composepipercompose

compose

compose 函数实现了函数复合:它将一个函数序列转换成单个函数。它执行从最后一个函数到第一个函数的复合。

from functools import reduce

def compose(*funcs):
    return reduce(lambda f, g: lambda *args, **kwargs: f(g(*args, **kwargs)), funcs)

def inc(n):
    return n + 1

def is_even(n):
    return n % 2 == 0

def inc_even(n):
    return compose(inc, is_even)(n)

print(inc_even(7))

compose(inc,is_even) 正确检测出一个数字是否是偶数。如果该数字是偶数,它会将其递增,否则会返回原始输入。

pipe

compose 不同,pipe 执行从第一个函数到最后一个函数的复合。

def pipe(*funcs):
    def _pipe(*args, **kwargs):
        val = funcs[0](*args, **kwargs)
        for f in funcs[1:]:
            val = f(val)
        return val
    return _pipe

def triple(n):
    return n * 3

def square(n):
    return n ** 2

def triple_then_square(n):
    return pipe(triple, square)(n)

print(triple_then_square(3))

rcompose

rcompose 是相对于 compose 的反向复合,它从最后一个函数到第一个函数执行复合。这个函数可以用来一般化一个可变参数的 compose 或者 pipe 函数。

def rcompose(*funcs):
    return compose(*reversed(funcs))

def double(n):
    return n * 2

def square(n):
    return n ** 2

def double_then_square(n):
    return rcompose(double, square)(n)

print(double_then_square(3))

柯里化

柯里化是在数学和计算机科学中一种重要的思想,其中一个函数接收多个参数,并将它们变成一系列只接收一个参数的函数序列。任何多参函数都可以“柯里化”,柯里化就是逐步缩小参数范围的过程。

Python 中的函数式编程库 toolz 为我们提供了柯里化功能。

from toolz import curry

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

incr = add(1)
print(incr(2)) # 3

使用 curry 装饰器定义的函数在使用时可是与普通函数一样,但当它只接收部分参数或没有参数时,它会返回一个新函数,该函数接收剩下的参数。 这种技术在实现部分应用程序时非常有用,可将一个具有多个参数的函数转换为多个仅使用一个参数的累积函数。

from toolz import curry

def add(a, b, c):
    return a + b + c

curried = curry(add)
partial = curried(1, 2)
print(partial(3)) # 6

在上面的例子中,curriedadd 函数的柯里化版本,现在可以通过 curried 来部分应用程序。 调用 curried(1, 2)add 的前两个参数设置为 1 和 2。 返回值将是一个新的函数,该函数期望接收最后一个参数。 这个新函数可以等效于 add(1, 2, 3)

可以使用 toolzcurrycurry2 装饰器来实现柯里化。

from toolz import curry

@curry
def add(a, b, c):
    return a + b + c

partial = add(1)(2)

在这个例子中,使用 @curry 装饰器定义了一个 add 函数,并先将其应用到 1,之后使用它来部分地填充了一个值为 2 的参数。

柯里化允许我们更容易地使用一些已有的函数,例如,可以通过组合原始函数,然后用新的函数进行一些操作。

from toolz import curry, compose

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

@curry
def multiply(x, y):
    return x * y

add_two_numbers_and_multiply_by_three = compose(multiply(3), add)
result = add_two_numbers_and_multiply_by_three(1)(2)
print(result) # 9

在上述例子中,add_two_numbers_and_multiply_by_three 是通过使用 compose 函数和两个工作函数 addmultiply 创建的。 这个新函数将两个数字相加,然后再将结果乘以 3。 最后,它将通过 result 变量进行输出。

以上就是 Python 函数式编程中的函数复合和柯里化的全面攻略。