Python 05_Python中lambda匿名函数用法详解

一、lambda 函数原理

1.1 lambda 函数简介

lambda 函数是一种匿名函数(即:没有名称定义),也称为内联函数或者函数字面量,它可以接受任意数量的参数,但与普通函数不同,它只计算并返回一个表达式,通常用于那些简单的、一次性的函数,这样可以避免定义一个完整的函数。

例如,如果你只是想对一个列表的每个元素进行平方操作,你可以使用Lambda函数,而不需要定义一个单独的函数。

总之,lambda函数为编程提供了一种灵活、简洁的方式来定义和使用函数,它使得程序员对编码中的那些一次性的操作,更加得心应手。

1.2 lambda函数的语法

lambda函数的一般语法很简单,lambda关键字定义,后面跟着参数列表和一个表达式。

1
lambda arguments: expression

其中:

  • lambda 是定义lambda函数的关键字,与普通函数中 def 类似。
  • arguments 是lambda函数的参数列表,支持传递位置和关键字参数,与普通函数一样,可以有零个或多个参数,多个参数之间用逗号分隔。
  • expression 是lambda函数的表达式,即函数的具体实现逻辑。表达式中出现的参数需要在 arguments 列表中有定义,并且表达式只能是单行的,只能有一个表达式。

Tips: 通常来说我们会将 lambda 函数作为参数传递给高阶函数(接受其他函数作为参数的函数),例如 Python 内置函数,如 filter()、map() 或 reduce()等

1.3 lambda 函数如何工作

看一个简单的 lambda 函数示例:

1
2
3
>>> lambda x: x + 1
<function <lambda> at 0x10d9125e0>
>>> 

上面的 lambda 函数接受一个参数,将其递增 1,然后返回结果,它是以下带有 def 和 return 关键字的普通函数的更简单版本:

1
2
def increment_by_one(x):
    return x + 1

到目前我们的 lambda 函数 lambda x: x + 1 只创建一个函数对象,不返回任何内容,这是因为我们没有为其参数 x 提供任何值(参数)。让我们先分配一个变量,将它传递给 lambda 函数,看看这次我们得到了什么:

1
2
3
4
>>> a = 1
>>> lambda x: a + 1
<function <lambda> at 0x10d94db80>
>>> 

lambda 函数没有像我们预期的那样返回 3,而是返回了函数对象本身及其内存位置,可以看出这不是调用 lambda 函数的正确方法。要将参数传递给 lambda 函数,执行它并返回结果,我们应该使用以下语法:

1
2
3
>>> (lambda x: x + 1)(2)
3
>>> 

虽然 lambda 函数的参数没有用括号括起来,但当调用它时,会在 lambda 函数的整个构造以及传递给它的参数周围添加括号。

上面代码中要注意的另一件事是,使用 lambda 函数,可以在创建函数后立即执行该函数并接收结果,这就是所谓的立即调用函数执行。

也可以创建一个带有多个参数的 lambda 函数,在这种情况下,用逗号分隔函数定义中的参数。当执行这样一个 lambda 函数时,以创建时相同的顺序列出相应的参数,并用逗号分隔它们:

1
2
3
>>> (lambda x, y, z: x + y + z)(3, 8, 1)
12
>>> 

也可以使用 lambda 函数来执行条件操作。下面是一个简单 if-else 函数的 lambda 示例:

1
2
3
4
5
>>> (lambda x: x if(x > 10) else 10)(5)
10
>>> (lambda x: x if(x > 10) else 10)(12)
12
>>> 

如果存在多个条件(if-elif-…-else),必须嵌套它们:

1
2
3
>>> (lambda x: x * 10 if x > 10 else (x * 5 if x < 5 else x))(11)
110
>>> 

但是上面的写法,又令代码变得难以阅读,所以 lambda 更适合简单的处理逻辑。对于复杂的处理逻辑,应该编写 def 函数进行处理(尽管 def 函数比相应的 lambda 函数增加了更多行,但它更容易阅读)。

可以将 lambda 函数分配给一个变量,然后将该变量作为普通函数调用:

1
2
3
4
>>> increment = lambda x: x + 1
>>> increment(2)
3
>>> 

但是根据 Python 代码的 PEP 8 样式规则,这是一种不好的做法

Tips: 赋值语句的使用消除了 lambda 表达式相对于显式 def 语句所能提供的唯一好处(即,它可以嵌入到更大的表达式中)

因此如果确实需要存储一个函数以供进一步使用,最好定义一个等效的普通函数,而不是将 lambda 函数分配给变量。

二、lambda函数的用法

2.1 作为参数传递给其它函数

lambda函数 常用于将简单的逻辑作为参数传递给高阶函数,如 filter()、map() 和 reduce() 等。

  • 带有 filter() 函数的 lambda

Tips: Python 中的 filter() 函数需要两个参数,运行 filter() 函数 将得到一个过滤器对象

  • 定义过滤条件的函数
  • 函数在其上运行的可迭代对象
1
2
3
4
>>> lst = [33, 3, 22, 2, 11, 1]
>>> filter(lambda x: x > 10, lst)
<filter object at 0x10d93efd0>
>>> 

为了从过滤器对象中获取一个新的迭代器,并且原始迭代器中的所有项都满足预定义的条件,我们需要将过滤器对象传递给 Python 标准库的相应函数:list()、tuple()、set ()、frozenset() 或 sorted()(返回排序列表)

1
2
3
4
5
6
7
8
>>> lst = [33, 3, 22, 2, 11, 1]
>>> sorted(filter(lambda x: x > 10, lst))
[11, 22, 33]
>>> tuple(filter(lambda x: x > 10, lst))
(33, 22, 11)
>>> list(filter(lambda x: x % 2 == 0, lst)) # 使用 lambda 函数和 filter() 函数筛选出列表中的偶数
[22, 2]
>>>
  • 带有 map() 函数的 lambda

Tips: 使用 Python 中的 map() 函数对可迭代的每个项目执行特定操作。它的语法与 filter() 相同:一个要执行的函数和一个该函数适用的可迭代对象。

  • map() 函数返回一个 map 对象,我们可以通过将该对象传递给相应的 Python 函数来从中获取一个新的迭代:list()、tuple()、set()、frozenset() 或 sorted() 等
  • 与 filter() 函数一样,我们可以从 map 对象中提取与原始类型不同类型的可迭代对象,并将其分配给变量。
1
2
3
4
5
6
7
8

# 使用 lambda 函数和 map() 函数将列表中的每个元素都平方
>>> lst = [1, 2, 3, 4, 5]
>>> map(lambda x: x * 10, lst)
<map object at 0x10d93eb20>
>>> tuple(map(lambda x: x * 10, lst))
(10, 20, 30, 40, 50)
>>> 

map() 和 filter() 函数之间的一个重要区别是第一个函数总是返回与原始函数相同长度的迭代。因此由于 pandas Series 对象也是可迭代的,我们可以在 DataFrame 列上应用 map() 函数来创建一个新列:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import pandas as pd
df = pd.DataFrame({'col1': [1, 2, 3, 4, 5], 'col2': [0, 0, 0, 0, 0]})
print(df)
df['col3'] = df['col1'].map(lambda x: x * 10)
print(df)

# 当然要在上述情况下获得相同的结果,也可以使用 apply() 函数:
df['col3'] = df['col1'].apply(lambda x: x * 10)
print(df)

# 还可以根据某些条件为另一列创建一个新的 DataFrame 列,对于下面的代码,可以互换使用 map() 或 apply() 函数:
df['col4'] = df['col3'].map(lambda x: 30 if x < 30 else x)
print(df)
  • lambda 与 filter函数和map函数结合使用
1
2
3
4
>>> squares = map(lambda x: x**2, range(10))
>>> filters = filter(lambda x: x>5 and x<50, squares)
>>> list(filters)
[9, 16, 25, 36, 49]
  • 带有 reduce() 函数的 lambda

Tips: Python中 reduce() 函数与 functools Python 模块相关,它的工作方式如下:

  • 对可迭代对象的前两项进行操作并保存结果
  • 对保存的结果和可迭代的下一项进行操作
  • 以这种方式在值对上进行,直到所有项目使用可迭代的(递归)

该函数与前两个函数具有相同的两个参数:一个函数和一个可迭代对象。但是与前面的函数不同的是,这个函数不需要传递给任何其他函数,直接返回结果标量值:

1
2
3
from functools import reduce
lst = [1, 2, 3, 4, 5]
reduce(lambda x, y: x + y, lst)

Tips: 需要注意的是,reduce() 函数总是需要一个带有两个参数的 lambda 函数,而且必须首先从 functools Python 模块中导入它

  • 结合sorted函数使用: lambda函数用于指定对列表中所有元素进行排序的准则
1
2
3
>>> info = [('James',32), ('Alies',20), ('Wendy',25)]
>>> sorted(info, key=lambda age:age[1])  # 按照第二个元素,索引为1排序
[('Alies', 20), ('Wendy', 25), ('James', 32)]

2.2 在高阶函数中使用 lambda 函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 使用Lambda函数定义一个自定义的排序规则
students = [
    {'name': 'Tiyong', 'grade': 90},
    {'name': 'Bob', 'grade': 85},
    {'name': 'Toy', 'grade': 95}
]

# 按照学生的成绩进行排序
sorted_students = sorted(students, key=lambda x: x['grade'], reverse=True)
print(sorted_students)

# 输出:[{'name': 'Toy', 'grade': 95}, {'name': 'Tiyong', 'grade': 90}, {'name': 'Bob', 'grade': 85}]