Python 函数式编程

117 阅读4分钟

在青训营的课程学习里,接触到了 Python 函数式编程这一独特且强大的编程范式,它与传统的命令式编程有所不同,有着自己独特的思维方式和优势,今天就来详细梳理一下所学的重点内容以及对应的代码示例。

一、函数式编程的概念与特点

函数式编程强调将计算视为函数的求值,避免使用会产生副作用的语句(如修改全局变量等),主要依靠函数的组合、映射、过滤等来处理数据,具有不可变数据、纯函数、高阶函数等重要特点。

纯函数

纯函数是函数式编程的核心概念之一,它指的是对于相同的输入,总是返回相同的输出,并且在执行过程中没有副作用(不会对外部环境产生影响,比如修改外部变量等)。例如下面这个简单的计算两个数之和的函数就是纯函数:

def add_numbers(a, b):
    return a + b

无论何时调用 add_numbers(3, 5),它都会返回 8,而且函数内部没有去修改任何外部定义的变量,仅仅是基于输入参数进行计算并返回结果。

二、高阶函数

高阶函数是指那些可以接收函数作为参数或者返回函数作为结果的函数,Python 中内置了不少高阶函数,它们极大地增强了代码的灵活性和复用性。

map() 函数

map() 函数接收一个函数和一个可迭代对象(比如列表)作为参数,它会将函数依次应用到可迭代对象的每个元素上,并返回一个新的可迭代对象(在 Python 3 中返回的是迭代器),示例如下:

# 定义一个将元素乘以2的函数
def double(x):
    return x * 2

nums = [1, 2, 3, 4, 5]
result = map(double, nums)
# 将迭代器转换为列表查看结果(在Python 3中需要手动转换)
print(list(result))
# 输出为 [2, 4, 6, 8, 10],每个元素都被 double 函数处理了一遍

filter() 函数

filter() 函数用于根据指定的条件筛选可迭代对象中的元素,它接收一个返回布尔值的函数和一个可迭代对象作为参数,返回满足条件的元素组成的新的可迭代对象。比如我们要筛选出列表中的偶数:

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

nums = [1, 2, 3, 4, 5]
even_nums = filter(is_even, nums)
print(list(even_nums))
# 输出为 [2, 4],只有偶数元素被筛选出来了

reduce() 函数(需要从 functools 模块导入)

reduce() 函数用于对可迭代对象中的元素进行累积计算,它接收一个有两个参数的函数和一个可迭代对象作为参数,将可迭代对象中的前两个元素传递给函数进行计算,然后将计算结果和下一个元素再传递给函数继续计算,依次类推,最终返回一个累积的结果。例如计算列表中所有元素的乘积:

from functools import reduce

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

nums = [1, 2, 3, 4]
product = reduce(multiply, nums)
print(product)
# 输出为 24,即 1 * 2 * 3 * 4 的结果

三、匿名函数(Lambda 表达式)

为了更简洁地定义一些简单的函数,尤其是在作为高阶函数的参数时,Python 提供了 Lambda 表达式,也就是匿名函数。它的语法形式为 lambda 参数列表: 表达式,例如上面的 double 函数可以用 Lambda 表达式写成:

nums = [1, 2, 3, 4, 5]
result = map(lambda x: x * 2, nums)
print(list(result))
# 同样能得到 [2, 4, 6, 8, 10] 的结果

还有筛选偶数的例子也可以改写为:

nums = [1, 2, 3, 4, 5]
even_nums = filter(lambda x: x % 2 == 0, nums)
print(list(even_nums))
# 输出 [2, 4]

四、函数式编程的优势与应用场景

函数式编程的优势在于代码更加简洁、易读、易于测试和维护,因为纯函数的特性使得函数之间的依赖关系更加清晰,不用担心函数调用过程中会意外修改其他地方的数据。它在处理数据集合(如列表、字典等)、数据转换、并行计算(因为没有副作用,更便于进行分布式或多线程处理)等场景中应用广泛。

比如在处理大量数据的清洗和转换工作时,使用函数式编程的 mapfilter 等函数可以高效地按照特定规则对数据进行处理,代码逻辑一目了然。