专栏名称: 新语数据故事汇
《新语数据故事汇,数说新语》科普数据科学、讲述数据故事,深层次挖掘数据价值。
目录
相关文章推荐
51好读  ›  专栏  ›  新语数据故事汇

一文带您了解Python的函数式编程:理解lambda、map()、filter()和reduce()

新语数据故事汇  · 公众号  ·  · 2024-08-18 14:01

正文

函数式编程在数据处理领域中扮演着重要的角色,其优势在于能以简洁和直观的方式处理和转换数据。通过将数据转换操作封装在纯函数中,函数式编程避免了副作用和可变状态,提升了代码的可维护性和可读性。在处理数据时,函数式编程提供了强大的工具,如 lambda、 map() filter() reduce() ,这些工具允许开发者高效地应用操作、筛选和归约数据集合。利用这些函数,数据处理可以变得更加简洁、模块化。这种编程范式不仅有助于编写更清晰的代码,还能帮助开发者应对复杂的数据处理任务,实现更高效的数据流转和分析。

什么是函数式编程?

纯函数是指输出值完全由输入值决定,并且没有任何可观察的副作用的函数。在函数式编程中,程序主要由纯函数的计算组成。计算通过嵌套或组合的函数调用进行,而不会改变状态或可变数据。

函数式编程范式之所以受欢迎,是因为它相对于其他编程范式有几个优势。函数式代码具有以下特点:

  • 高级抽象 :您描述的是想要的结果,而不是明确指定如何一步步达成这个结果。单个语句通常简洁但功能强大。

  • 透明性 :纯函数的行为可以通过其输入和输出来描述,而无需依赖中间值。这消除了副作用的可能性,并有助于调试。

  • 并行化 :不引发副作用的例程可以更容易地彼此并行运行。

许多编程语言都在一定程度上支持函数式编程。在某些语言中,几乎所有代码都遵循函数式编程范式。Haskell 就是这样的例子。而 Python 则同时支持函数式编程和其他编程模型。

虽然函数式编程的详细描述确实较为复杂,但这里的目标并不是提供严格的定义,而是展示如何在 Python 中进行函数式编程。

Python 对函数式编程的支持如何?

为了支持函数式编程,如果一种编程语言中的函数能够做到以下两点,将会非常有利:

  1. 接受另一个函数作为参数

  2. 返回另一个函数给调用者

Python 在这两个方面都表现得很好。在 Python 中,一切皆为对象,所有对象在 Python 中的地位基本上是平等的,函数也不例外。

在 Python 中,函数是第一类公民。这意味着函数具有与字符串和数字等值相同的特性。任何可以对字符串或数字进行的操作,也可以对函数进行。

例如,您可以将一个函数赋值给一个变量,然后可以像使用该函数一样使用该变量:

def func():    print("I am function func()!")

func()
another_name = funcanother_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 行显示了







请到「今天看啥」查看全文