函数式编程在数据处理领域中扮演着重要的角色,其优势在于能以简洁和直观的方式处理和转换数据。通过将数据转换操作封装在纯函数中,函数式编程避免了副作用和可变状态,提升了代码的可维护性和可读性。在处理数据时,函数式编程提供了强大的工具,如 lambda、
map()
、
filter()
和
reduce()
,这些工具允许开发者高效地应用操作、筛选和归约数据集合。利用这些函数,数据处理可以变得更加简洁、模块化。这种编程范式不仅有助于编写更清晰的代码,还能帮助开发者应对复杂的数据处理任务,实现更高效的数据流转和分析。
什么是函数式编程?
纯函数是指输出值完全由输入值决定,并且没有任何可观察的副作用的函数。在函数式编程中,程序主要由纯函数的计算组成。计算通过嵌套或组合的函数调用进行,而不会改变状态或可变数据。
函数式编程范式之所以受欢迎,是因为它相对于其他编程范式有几个优势。函数式代码具有以下特点:
-
高级抽象
:您描述的是想要的结果,而不是明确指定如何一步步达成这个结果。单个语句通常简洁但功能强大。
-
透明性
:纯函数的行为可以通过其输入和输出来描述,而无需依赖中间值。这消除了副作用的可能性,并有助于调试。
-
并行化
:不引发副作用的例程可以更容易地彼此并行运行。
许多编程语言都在一定程度上支持函数式编程。在某些语言中,几乎所有代码都遵循函数式编程范式。Haskell 就是这样的例子。而 Python 则同时支持函数式编程和其他编程模型。
虽然函数式编程的详细描述确实较为复杂,但这里的目标并不是提供严格的定义,而是展示如何在 Python 中进行函数式编程。
Python 对函数式编程的支持如何?
为了支持函数式编程,如果一种编程语言中的函数能够做到以下两点,将会非常有利:
-
接受另一个函数作为参数
-
返回另一个函数给调用者
Python 在这两个方面都表现得很好。在 Python 中,一切皆为对象,所有对象在 Python 中的地位基本上是平等的,函数也不例外。
在 Python 中,函数是第一类公民。这意味着函数具有与字符串和数字等值相同的特性。任何可以对字符串或数字进行的操作,也可以对函数进行。
例如,您可以将一个函数赋值给一个变量,然后可以像使用该函数一样使用该变量:
def func():
print("I am function func()!")
func()
another_name = func
another_name()
在第 7 行,通过
another_name = func
这条语句创建了一个新的引用,指向函数
func()
,这个引用名为
another_name
。随后,您可以通过
func
或
another_name
这两个名称来调用这个函数,如第 5 行和第 8 行所示。
您可以使用
print()
将函数显示在控制台上,还可以将函数作为元素包含在复合数据对象(例如列表)中,甚至可以将其用作字典的键:
def func():
print("I am function func()!")
print("cat", func, 42)
objects = ["cat", func, 42]
print(objects[1])
objects[1]()
d = {"cat": 1, func: 2, 42: 3}
d[func]
在这个示例中,
func()
出现在与值
"cat"
和
42
相同的上下文中,python解释器都能正常处理它。
在当前讨论的上下文中,关键在于 Python 中的函数满足了前面提到的对函数式编程有利的两个标准。您可以将一个函数作为参数传递给另一个函数:
def inner():
print("I am function inner()!")
def outer(function):
function()
outer(inner)
以上示例的过程如下:
-
在第 7 行中,
inner()
被作为参数传递给
outer()
。
-
在
outer()
内部,Python 将
inner()
绑定到函数参数
function
。
-
然后
outer()
可以直接使用
function
来调用
inner()
。
这被称为
函数组合
。需要注意的是,您传递的是函数对象本身作为参数。如果您使用括号来调用函数对象,那么您传递的将不是函数对象,而是它的返回值。
当您将一个函数传递给另一个函数时,被传递的函数有时被称为回调函数(callback),因为对内部函数的调用可以修改外部函数的行为。
一个很好的例子是 Python 中的
sorted()
函数。通常,如果您将一个字符串列表传递给
sorted()
,它会按照字典顺序进行排序:
然而,
sorted()
接受一个可选的
key
参数,该参数指定一个回调函数作为排序的依据。因此,例如,您可以按照字符串的长度进行排序:
animals = ["ferret", "vole", "dog", "gecko"]
sorted(animals, key=len)
sorted()
还可以接受一个可选的参数,用于指定是否以反向顺序排序。但是,您也可以通过定义自己的回调函数来实现相同的效果,例如编写一个函数来反转
len()
的排序顺序:
animals = ["ferret", "vole", "dog", "gecko"]
sorted(animals, key=len, reverse=True)
def reverse_len(s):
return -len(s)
sorted(animals, key=reverse_len)
正如您可以将一个函数作为参数传递给另一个函数一样,函数也可以指定另一个函数作为其返回值:
def outer():
def inner():
print("I am function inner()!")
# Function outer() returns function inner()
return inner
function = outer()
print( function )
function()
outer()()
在这个示例中发生的过程如下:
-
第 2 到 3 行:
outer()
定义了一个局部函数
inner()
。
-
第 5 行:
outer()
将
inner()
作为返回值返回。
-
第 87行:您将
outer()
的返回值赋给变量
function
。
-
之后,您可以通过
function
间接调用
inner()
,如第 10 行所示。也可以通过
outer()
的返回值直接调用
inner()
,如第 12 行所示,无需中间赋值。
如您所见,Python 拥有支持函数式编程的所有必要组件。但在深入函数式代码之前,还有一个概念很有帮助,那就是
lambda 表达式
。
使用 lambda 定义匿名函数
函数式编程的核心是调用和传递函数,因此通常涉及大量的函数定义。您可以像往常一样使用
def
关键字定义函数。
有时,能够在不需要给函数命名的情况下定义一个匿名函数会很方便。在 Python 中,您可以使用
lambda
表达式来实现这一点。
lambda
表达式的语法如下:
lambda <parameter_list>: <expression>
以下表格总结了
lambda
表达式的各个部分:
组件
|
说明
|
lambda
|
引入
lambda
表达式的关键字
|
|
可选的用逗号分隔的参数名称列表
|
:
|
标点符号,用于分隔
和
|
|
通常涉及
中名称的表达式,表示
lambda
函数的返回值
|
lambda
表达式的值是一个可调用的函数,类似于使用
def
关键字定义的函数。它接受由
指定的参数,并返回由
指定的值。
以下是一个简单的示例:
第 1 行的语句只是
lambda
表达式本身。
内置的 Python 函数
callable()
如果传递给它的参数看起来是可调用的,则返回
True
,否则返回
False
。第 3 行显示了