使用lambda函数还是嵌套函数('def')更好?
我通常使用lambda函数,但有时候也会用嵌套函数,它们似乎能实现相同的功能。
下面是一些简单的例子,如果把它们放在另一个函数里,它们的功能是一样的:
Lambda函数
>>> a = lambda x : 1 + x
>>> a(5)
6
嵌套函数
>>> def b(x): return 1 + x
>>> b(5)
6
使用这两种方式有什么优缺点吗?比如性能、可读性、限制、统一性等等?
这真的重要吗?如果不重要,那是不是违背了Python的一个原则:
16 个回答
在这次采访中, 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 秒 :)
从实际角度来看,我觉得有两个主要区别:
第一个区别是它们的功能和返回值:
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
。但通常情况下,如果是这样的话,使用一个普通的函数会更好。
如果你需要给一个 lambda
取个名字,最好用 def
。其实,def
只是一个语法上的简化,效果是一样的,而且它更灵活、更容易读懂。
lambda
通常用于那些“用一次就扔掉”的函数,这种函数是没有名字的。
不过,这种情况非常少见。你很少需要传递没有名字的函数对象。
内置的 map()
和 filter()
需要函数对象,但列表推导式和生成器表达式通常比这些函数更容易理解,而且可以满足所有需求,不需要用到 lambda
。
如果你真的需要一个小的函数对象,建议使用 operator
模块里的函数,比如用 operator.add
代替 lambda x, y: x + y
。
如果你还有一些 lambda
的用法没有被提到,考虑写一个 def
,这样会更容易理解。如果这个函数比 operator
模块里的函数复杂,使用 def
可能更好。
所以,实际上,好的 lambda
使用场景非常少。