使用lambda函数还是嵌套函数('def')更好?

140 投票
16 回答
99893 浏览
提问于 2025-04-11 09:25

我通常使用lambda函数,但有时候也会用嵌套函数,它们似乎能实现相同的功能。

下面是一些简单的例子,如果把它们放在另一个函数里,它们的功能是一样的:

Lambda函数

>>> a = lambda x : 1 + x
>>> a(5)
6

嵌套函数

>>> def b(x): return 1 + x

>>> b(5)
6

使用这两种方式有什么优缺点吗?比如性能、可读性、限制、统一性等等?

这真的重要吗?如果不重要,那是不是违背了Python的一个原则:

应该有一种——而且最好只有一种——明显的方法来做到这一点。.

16 个回答

35

在这次采访中, Guido van Rossum 表示他希望自己当初没有让 'lambda' 这个功能进入 Python:

问:你对 Python 哪个功能最不满意?

有时候我太快接受了一些贡献,后来才意识到这是个错误。一个例子就是一些函数式编程的特性,比如 lambda 函数。lambda 是一个关键字,可以让你创建一个小的匿名函数;像 map、filter 和 reduce 这样的内置函数可以对列表等序列类型运行一个函数。

实际上,这个功能并没有那么好用。Python 只有两种作用域:局部和全局。这让写 lambda 函数变得很麻烦,因为你通常想访问定义 lambda 时所在的作用域中的变量,但由于只有这两种作用域,你却无法做到。虽然有办法解决这个问题,但那种方法有点笨拙。通常在 Python 中,使用 for 循环比搞这些 lambda 函数要简单得多。map 和其他类似的函数只有在已经有一个内置函数能完成你想要的操作时才好用。

在我看来,lambda 有时候很方便,但通常会牺牲可读性。你能告诉我这段代码在做什么吗:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

我写的这段代码,花了我一分钟才搞明白。这是来自 Project Euler 的题目——我不想说是哪道题,因为我讨厌剧透,但它运行的时间是 0.124 秒 :)

39

从实际角度来看,我觉得有两个主要区别:

第一个区别是它们的功能和返回值:

  • def 是一个关键字,它不返回任何东西,只是在本地命名空间中创建一个“名字”。

  • lambda 是一个关键字,它返回一个函数对象,并且不会在本地命名空间中创建“名字”。

所以,如果你需要调用一个接受函数对象的函数,唯一可以用一行 Python 代码实现的方法就是使用 lambda。用 def 是无法做到的。

在一些框架中,这种用法其实很常见;比如,我经常使用 Twisted,所以像这样做

d.addCallback(lambda result: setattr(self, _someVariable, result))

是很常见的,而且用 lambda 更简洁。

第二个区别是关于函数的实际功能限制。

  • 用 'def' 定义的函数可以包含任何 Python 代码。
  • 用 'lambda' 定义的函数必须是一个表达式,因此不能包含像 print、import、raise 这样的语句。

例如,

def p(x): print x

可以正常工作,而

lambda x: print x

会导致语法错误。

当然,也有一些变通的方法,比如用 sys.stdout.write 替代 print,或者用 __import__ 替代 import。但通常情况下,如果是这样的话,使用一个普通的函数会更好。

150

如果你需要给一个 lambda 取个名字,最好用 def。其实,def 只是一个语法上的简化,效果是一样的,而且它更灵活、更容易读懂。

lambda 通常用于那些“用一次就扔掉”的函数,这种函数是没有名字的。

不过,这种情况非常少见。你很少需要传递没有名字的函数对象。

内置的 map()filter() 需要函数对象,但列表推导式生成器表达式通常比这些函数更容易理解,而且可以满足所有需求,不需要用到 lambda

如果你真的需要一个小的函数对象,建议使用 operator 模块里的函数,比如用 operator.add 代替 lambda x, y: x + y

如果你还有一些 lambda 的用法没有被提到,考虑写一个 def,这样会更容易理解。如果这个函数比 operator 模块里的函数复杂,使用 def 可能更好。

所以,实际上,好的 lambda 使用场景非常少。

撰写回答