如果你刚开始使用 Python,那么理解什么是 lambda 可能会有些混乱。
lambda 也称为匿名函数,这是因为 lambda 没有名称。要在 Python 中定义 lambda,你可以使用关键字 lambda 后跟一个或多个参数、一个冒号 (:) 和一个表达式。
我们将从一个简单的 lambda 函数示例开始,以熟悉其语法,然后我们将了解 Python lambda 函数如何适用于不同的场景。
如何在 Python 中使用 Lambda
让我们从 lambda 函数的语法开始。
lambda 函数以lambda关键字开头,后跟逗号分隔的参数列表。下一个元素是一个冒号(:),后跟一个表达式。
lambda :
如你所见,可以在一行中定义一个 lambda 函数。
让我们看一个非常简单的 lambda,它将数字 x(参数)乘以 2:
lambda x : 2*x
运行返回了一个函数对象。有趣的是,当我定义一个 lambda 时,我不需要 return 语句作为表达式的一部分。
如果我在表达式中包含 return 语句会怎样?
我们收到语法错误。所以,不需要在 lambda 中包含 return 。
如何在 Python 中调用 Lambda 函数
我们已经了解了如何定义 lambda,但我们如何调用它呢?
首先,我们将在不将函数对象分配给变量的情况下执行此操作。为此,我们只需要使用括号。
(lambda x : 2*x)(2)
我们将用括号将 lambda 表达式括起来,然后用括号括起我们要传递给 lambda 的参数。
这是我们运行时的输出:
我们还有另一种选择。我们可以将lambda函数返回的函数对象赋值给一个变量,然后使用变量名调用函数。
multiply = lambda x : 2*x
multiply(2)
这是我们运行时的输出:
将多个参数传递给 Lambda 函数
在前面的部分中,我们了解了如何定义和执行 lambda 函数。
我们还看到 lambda 可以有一个或多个参数,让我们看一个有两个参数的例子。
创建一个将参数 x 和 y 相乘的 lambda:
(lambda x, y : x*y)(2,3)
这是我们运行时的输出:
lambda 是一个IIFE(立即调用的函数表达式)。它基本上是一种表示 lambda 函数在定义后立即执行的方式。
Lambda 函数和常规函数之间的区别
在继续研究如何在 Python 程序中使用 lambda 之前,了解常规 Python 函数和 lambda 之间的关系很重要。
让我们以相乘的例子为例:
lambda x, y : x*y
我们也可以使用def关键字将其编写为常规函数:
def multiply(x, y):
return x*y
与 lambda 形式相比,你会立即注意到三个不同之处:
- 使用 def 关键字时,我们必须为我们的函数指定一个名称。
- 这两个参数用括号括起来。
- 我们使用return语句返回函数的结果。
将我们的 lambda 函数分配给一个变量是可选的
multiply_lambda = lambda x, y : x*y
让我们比较一下这两个函数的对象:
def multiply(x, y):
return x*y
multiply_lambda = lambda x, y : x*y
print(multiply)
print(multiply_lambda)
从上面的图我们可以看到一个区别:使用 def 关键字定义的函数由名称“multiply”标识,而 lambda 函数由通用
让我们看看type() 函数在应用于这两个函数时返回的内容:
所以,这两个函数的类型是一样的。
可以在 Python Lambda 中使用 If Else 吗?
lambda x: x if x > 2 else 2*x
如果 x 大于 2,则此 lambda 应返回 x,否则应返回 x 乘以 2。
首先,让我们确认它的语法是否正确
测试一下我们的功能:
同时你可以看到,如果我们让 lambda 表达式变得越来越复杂,我们的代码会变得更难阅读。
如何用 Lambda 和 Map 替换 For 循环
在本节中,我们将看到 lambda 在应用于像Python 列表这样的可迭代对象时如何变得非常强大。
让我们从一个标准的 Python for 循环开始,循环遍历字符串列表的所有元素并创建一个新列表,其中所有元素都是大写的。
names = ['Jack', 'Elio', 'Helen']
names_result = []
for name in names:
names_result.append(name.upper())
这是输出:
现在我们将编写相同的代码,但使用 lambda。为此,我们还将使用一个名为map的 Python 内置函数,其语法如下:
map(function, iterable, ...)
map 函数将另一个函数作为第一个参数,然后是一个可迭代列表。在这个具体的例子中,我们只有一个可迭代对象,即名字列表。
将另一个函数作为参数的函数称为高阶函数。
这听起来可能很复杂,这个例子将帮助你理解它是如何工作的。
那么,map函数有什么作用呢?
map 函数返回一个可迭代对象,它是作为第一个参数传递给可迭代对象的每个元素的函数的结果。
在我们的场景中,我们将作为第一个参数传递的函数将是一个 lambda 函数,它将其参数转换为大写格式。作为可迭代的,我们将传递我们的list。
map(lambda x: x.upper(), names)
上面执行会返回一个map对象。我们怎样才能取回列表呢?
我们可以将map对象转换为列表
list(map(lambda x: x.upper(), names))
很明显,与我们使用 for 循环的代码相比,使用 map 和 lambda 可以使这段代码更加简洁。
将 Lambda 函数与字典结合使用
我想尝试使用 lambda 函数从字典列表中提取特定字段。
这是很多场景都可以应用的东西,下面是一个列表里面包含字典。
people = [{'firstname':'John', 'lastname':'Ross'}, {'firstname':'Mark', 'lastname':'Green'}]
我又一次可以将 map 内置函数与 lambda 函数一起使用。
lambda 函数将一个字典作为参数并返回 firstname 键的值。
lambda x : x['firstname']
完整的表达式是:
firstnames = list(map(lambda x : x['firstname'], people))
运行输出:
将 Lambda 传递给过滤器内置函数
另一个可以与 lambda 一起使用的 Python 内置函数是filter 函数。
下面你可以看到它的语法需要一个函数和一个可迭代对象:
filter(function, iterable)
这里的想法是创建一个表达式,给定一个列表返回一个新列表,其元素匹配 lambda 函数定义的特定条件。
例如,给定一个数字列表,我想返回一个只包含负数的列表。
这是我们将使用的 lambda 函数:
lambda x : x < 0
让我们尝试执行此 lambda 并将几个数字传递给它,以便清楚 lambda 返回的内容。
(lambda x : x < 0)(-1) # True
(lambda x : x < 0)(3) # False
我们的 lambda 返回一个布尔值:
- 如果论证是否定的,则为真。
- 如果参数为正则为假。
现在,让我们将此 lambda 应用于过滤器函数:
numbers = [1, 3, -1, -4, -5, -35, 67]
negative_numbers = list(filter(lambda x : x < 0, numbers))
print(negative_numbers)
我们得到了预期的结果,一个包含所有负数的列表。
Reduce 和 Lambda 如何与列表一起使用
另一个常见的 Python 内置函数是属于functools 模块的reduce 函数。
reduce(function, iterable[, initializer])
reduce 函数有什么作用?,reduce函数会对参数迭代器中的元素进行积累。
ruduce函数的定义如下:
functools.reduce(function, iterable[, initializer])
为了在实践中理解它,我们将应用一个简单的 lambda 来计算两个数字的总和到数字列表:
from functools import reduce
reduce(lambda x,y: x+y, [3, 7, 10, 12, 5])
运行输出:
让我们看看我们是否也可以使用 reduce 函数来连接列表中的字符串:
from functools import reduce
reduce(lambda x,y: x + ' ' + y,
['This', 'is', 'a', 'tutorial', 'about', 'Python', 'lambdas'])
运行输出:
应用于类的 Lambda 函数
考虑到 lambda 可以用来代替常规的 Python 函数,我们可以将 lambda 用作类方法吗?
我将定义一个名为 Gorilla 的类,它包含一个构造函数和打印消息的运行方法:
class Gorilla:
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.weight = weight
def run(self):
print('{} starts running!'.format(self.name))
然后我创建了这个类的一个名为 Spartacus 的实例并在其上执行 run 方法:
Spartacus = Gorilla('Spartacus', 35, 150)
Spartacus.run()
输出是:
现在,让我们用 lambda 函数替换 run 方法:
class Gorilla:
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.weight = weight
run = lambda self: print('{} starts running!'.format(self.name))
在 Gorilla 类的实例上再次执行 run 方法,会看到输出消息完全相同。
将 Lambda 与排序函数一起使用
sorted 内置函数从可迭代对象返回一个排序列表。
让我们看一个简单的例子,我们将对包含一些行星名称的列表进行排序:
planets = ['saturn', 'earth', 'mars', 'jupiter'] # 排序函数按字母顺序对列表进行排序
sorted(planets)
运行输出:
现在,假设我们要根据不同的标准对列表进行排序,例如每个单词的长度。
为此,我们可以使用额外的参数键,它允许在进行任何比较之前提供一个应用于每个元素的函数。
sorted(planets, key=len)
# ['mars', 'earth', 'saturn', 'jupiter']
在这种情况下,我们使用了 len() 内置函数,这就是行星从最短到最长排序的原因。
那么,lambda 在哪里适合所有这些?
Lambda 是函数,因此它们可以与 key 参数一起使用。
例如,假设我想根据每个行星的第三个字母对我的列表进行排序。
sorted(planets, key=lambda p: p[2])
#['jupiter', 'earth', 'mars', 'saturn']
如果我想根据特定属性的值对字典列表进行排序怎么办?
people = [{'firstname':'John', 'lastname':'Ross'},
{'firstname':'Mark', 'lastname':'Green'}]
sorted(people, key=lambda x: x['lastname'])
在此示例中,我们根据姓氏键的值对字典列表进行了排序。
运行输出:
Python Lambda 和错误处理
在我们查看 lambda 和常规函数之间区别的部分中,我们看到了以下内容:
>>> multiply
>>> multiply_lambda
at 0x1014227a0>
其中 multiply 是一个常规函数,multiply_lambda 是一个 lambda 函数。
如你所见,常规函数的函数对象由名称标识,而 lambda 函数对象由通用
这也使得 lambda 函数的错误处理变得更加棘手,因为 Python 回溯不包括发生错误的函数的名称。
让我们创建一个常规函数并向其传递会导致 Python 解释器引发异常的参数:
def calculate_sum(x, y):
return x+y
print(calculate_sum(5, 'Not_a_number'))
当我在 Python shell 中运行此代码时,出现以下错误:
>>> def calculate_sum(x, y):
... return x+y
...
>>> print(calculate_sum(5, 'Not_a_number'))
Traceback (most recent call last):
File "", line 1, in
File "", line 2, in calculate_sum
TypeError: unsupported operand type(s) for +: 'int' and 'str'
从回溯中我们可以清楚地看到错误发生在 calculate_sum 函数的第 2 行。
现在,让我们用 lambda 替换这个函数:
calculate_sum = lambda x, y: x+y
print(calculate_sum(5, 'Not_a_number'))
输出是:
>>> calculate_sum = lambda x,y: x+y
>>> print(calculate_sum(5, 'Not_a_number'))
Traceback (most recent call last):
File "", line 1, in
File "", line 1, in
TypeError: unsupported operand type(s) for +: 'int' and 'str'
异常类型和错误消息是一样的,但是这次回溯告诉我们函数
将可变参数列表传递给 Python Lambda
在本节中,我们将了解如何向 Python lambda 提供可变参数列表。
要将可变数量的参数传递给 lambda,我们可以像使用常规函数一样使用*args :
lambda *args: max(args))(5, 3, 4, 10, 24)
当我们运行它时,我们得到传递给 lambda 的参数之间的最大值:
>>> (lambda *args: max(args))(5, 3, 4, 10, 24)
24
我们不一定要使用关键字 args。重要的是 args 之前的 * 在 Python 中代表可变数量的参数。
让我们通过用数字替换 args 来确认是否是这种情况:
>>> (lambda *numbers: max(numbers))(5, 3, 4, 10, 24)
24
Lambda 函数的更多示例
如果你想在 Python 程序中使用 lambda,这些示例应该会给你更多的想法。
给定一个 Linux 命令列表,只返回以字母“c”开头的命令:
>>> commands = ['ls', 'cat', 'find', 'echo', 'top', 'curl']
>>> list(filter(lambda cmd: cmd.startswith('c'), commands))
['cat', 'curl']
从带空格的逗号分隔字符串返回一个列表,其中包含不带空格的字符串中的每个单词:
>>> weekdays = "monday , tuesday, wednesday,thursday, friday, saturday ,sunday"
>>> list(map(lambda word: word.strip(), weekdays.split(',')))
['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
使用 Python range 函数生成数字列表并返回大于四的数字:
>>> list(filter(lambda x: x > 4, range(15)))
[5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
结论
在本篇文章中,我们了解了什么是 Python lambda,以及如何定义和执行它。
我们浏览了带有一个或多个参数的示例,我们还看到了 lambda 如何返回一个函数对象(不需要 return 语句)。
现在你知道 lambda 也称为匿名函数,因为当你定义它时,你不会将它绑定到一个名称。
此外,分析 Python 中常规函数和 lambda 函数之间的区别有助于我们更好地理解 lambda 的工作原理。
当你的代码中只需要一次时,使用 lambda 函数是很常见的。如果你需要在代码库中多次调用的函数,使用常规函数是避免代码重复的更好方法。
永远记住编写干净的代码是多么重要,任何人都可以快速理解的代码,以防将来出现需要快速修复的错误。
现在你可以在 lambda 表达式和常规函数之间做出选择,做出正确的选择!
如果你发现我的任何文章对你有帮助或者有用,麻烦点赞或者转发。 谢谢!