哪个更适合在Python中使用:lambda函数或嵌套函数('def')?

我主要使用lambda函数,但有时使用似乎提供相同行为的嵌套函数。

这里有一些微不足道的例子,他们在function上做同样的事情,如果在另一个函数中发现:

Lambda函数

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

嵌套function

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

使用其中一个有好处吗? (性能?可读性?限制?一致性?等)它甚至重要吗? 如果这样做没有违反Pythonic原则: “应该有一个,最好只有一个 – 明显的方式来做到这一点” 。

如果您需要将lambda分配给名称,请改为使用defdef只是一个赋值语句糖,所以结果是一样的,而且它们更加灵活可读。

lambda s可以使用一次,扔掉没有名字的函数。

不过,这个用例非常less见。 你很less需要传递未命名的函数对象。

内build的map()filter()需要函数对象,但列表推导生成器expression式通常比这些函数更具可读性,并且可以涵盖所有用例,而不需要lambdaexpression式。

对于你确实需要一个小函数对象的情况,你应该使用operator.add而不是lambda x, y: x + y

如果你仍然需要一些lambda没有覆盖,你可以考虑写一个def ,只是为了更可读。 如果函数比operator模块更复杂,则def可能更好。

所以,现实世界中好的lambda用例是非常罕见的。

实际上,对我来说有两个区别:

首先是关于他们做什么和他们回报什么:

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

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

因此,如果你需要调用一个带有函数对象的函数,那么在一行python代码中做的唯一方法就是使用lambdaexpression式。 def没有等价物。

在一些框架中,这实际上是相当普遍的; 例如,我使用了Twisted ,做了一些类似的事情

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

是相当普遍的,而且更加简洁。

第二个区别是关于实际function被允许做什么。

  • 用'def'定义的函数可以包含任何python代码
  • 用'lambda'定义的函数必须求值为一个expression式,因此不能包含print,import,raise等语句。

例如,

 def p(x): print x 

按预期工作,而

 lambda x: print x 

是一个SyntaxError。

当然,还有一些解决方法 – 用sys.stdout.writereplaceprint ,或者用__import__ import 。 但是通常情况下,你最好在这种情况下使用一个函数。

在这次采访中, Guido van Rossum说他希望他没有让'lambda'进入Python:

Q.你最不喜欢Python的哪个特性?

有时我接受稿件太快了,后来才意识到这是一个错误。 一个例子是一些函数式编程特性,比如lambda函数。 lambda是一个关键字,可以让你创build一个小的匿名函数; 内置函数(如map,filter和reduce)在序列types(如列表)上运行函数。

实际上,结果并不好。 Python只有两个范围:本地和全局。 这使得编写lambda函数变得很痛苦,因为你经常要访问定义了lambda的范围内的variables,但是你不能因为这两个范围。 有一种解决办法,但这是一个混乱的东西。 Python中似乎更容易使用for循环,而不是乱用lambda函数。 地图和朋友只有在已经有内置function的时候才能正常工作。

恕我直言,Iambdas有时可以方便,但通常是方便的,可读性的代价。 你能告诉我这是什么吗?

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

我写了,花了一分钟才弄明白。 这是从欧拉项目 – 我不会说哪个问题,因为我讨厌破坏者,但它运行在0.124秒:)

对于n = 1000,这里是调用函​​数vs lambda的一些时间:

 In [11]: def f(a, b): return a * b In [12]: g = lambda x, y: x * y In [13]: %%timeit -n 100 for a in xrange(n): for b in xrange(n): f(a, b) ....: 100 loops, best of 3: 285 ms per loop In [14]: %%timeit -n 100 for a in xrange(n): for b in xrange(n): g(a, b) ....: 100 loops, best of 3: 298 ms per loop In [15]: %%timeit -n 100 for a in xrange(n): for b in xrange(n): (lambda x, y: x * y)(a, b) ....: 100 loops, best of 3: 462 ms per loop 

我同意nosklo的build议:如果你需要给函数一个名字,使用def 。 我保留lambda函数的情况下,我只是简单的代码片段传递给另一个函数,例如:

 a = [ (1,2), (3,4), (5,6) ] b = map( lambda x: x[0]+x[1], a ) 

性能:

lambda创build一个函数要比用def创build它要快一些。 区别在于def在locals表中创build一个名字条目。 由此产生的function具有相同的执行速度。


可读性:

对于大多数Python用户来说,Lambda函数的可读性稍差,但在某些情况下也更加简洁。 考虑从使用非function转换到function例程:

 # Using non-functional version. heading(math.sqrt(vx * vx + vy * vy), math.atan(vy / vx)) # Using lambda with functional version. fheading(v, lambda v: math.sqrt(vx * vx + vy * vy), lambda v: math.atan(vy / vx)) # Using def with functional version. def size(v): return math.sqrt(vx * vx + vy * vy) def direction(v): return math.atan(vy / vx) deal_with_headings(v, size, direction) 

正如您所看到的, lambda版本更短,更简单,因为您只需要将lambda v:添加到原始非function版本即可转换为function版本。 它也更加简洁。 但是请记住,很多Python用户会被lambda语法弄糊涂,所以在长度和实际复杂度上的损失可能会被同行编码人员混淆。


限制:

  • lambda函数只能使用一次,除非分配给一个variables名称。
  • 分配给variables名称的lambda函数没有def函数的优势。
  • lambdafunction可能难以或不可能腌制。
  • def函数的名字必须仔细select,以便合理的描述性和独特性,或者至less在其他范围内不被使用。

一致性:

Python主要避免函数式编程惯例,而采用程序性和简单的客观语义。 lambda操作符与这种偏见形成鲜明对比。 而且,作为已经普遍使用的def的替代, lambda函数增加了语法的多样性。 有些人会认为这不太一致。


预先存在的function:

正如其他人所指出的那样, lambda在现场的许多用途可以由operator或其他模块的成员来代替。 例如:

 do_something(x, y, lambda x, y: x + y) do_something(x, y, operator.add) 

在许多情况下,使用预先存在的函数可以使代码更具可读性。


Pythonic原理:“应该有一个,最好只有一个明显的方法来做到这一点”

这与真理原理的单一来源类似。 不幸的是,单一显而易见的做法原则一直是Python的渴望,而不是真正的指导原则。 考虑Python中非常强大的数组理解。 它们在function上等同于mapfilterfunction:

 [e for e in some_array if some_condition(e)] filter(some_array, some_condition) 

lambdadef是一样的。

这是一个意见的问题,但我会说,Python语言中的任何打算用于一般用途而不会明显破坏任何东西的东西是“Pythonic”就够了。

lambda的主要用途一直是简单的callback函数,而map,reduce,filter则需要函数作为参数。 列表理解成为常态,并且允许添加,如下所示:

 x = [f for f in range(1, 40) if f % 2] 

很难想象在日常使用中使用lambda的真实情况。 因此,我会说,避免lambda和创build嵌套函数。

在同意其他答案的同时,有时更具可读性。 下面是一个lambda派上用场的例子,在用例中我遇到了一个N​​维的defaultdict
这是一个例子:

 from collections import defaultdict d = defaultdict(lambda: defaultdict(list)) d['Foo']['Bar'].append(something) 

我发现它比为第二维创build一个def更可读。 这对于更高的尺寸来说更为重要。

我find的lambdas的一个用法是在debugging消息中。

由于lambda可以被懒惰评估,你可以有这样的代码:

 log.debug(lambda: "this is my message: %r" % (some_data,)) 

而不是可能是昂贵的:

 log.debug("this is my message: %r" % (some_data,)) 

即使debugging调用由于当前日志logging级别而没有生成输出,它也会处理格式string。

当然,如上所述,正在使用的日志logging模块必须支持lambdas作为“懒惰参数”(就像我的日志logging模块一样)。

对于按需内容价值创造的任何其他懒惰评估情况,可以应用相同的想法。

例如这个自定义的三元运算符:

 def mif(condition, when_true, when_false): if condition: return when_true() else: return when_false() mif(a < b, lambda: a + a, lambda: b + b) 

代替:

 def mif(condition, when_true, when_false): if condition: return when_true else: return when_false mif(a < b, a + a, b + b) 

与lambdas只有通过条件select的expression式将被评估,没有lambda将被评估。

当然,你可以简单地使用函数来代替lambdaexpression式,但是对于简短的expression式,lambdas是(c)精简的。

lambda的一个重要限制是它们除了expression式之外不能包含任何东西。 lambdaexpression式几乎不可能产生除了不重要的副作用以外的任何东西,因为它不能具有像定义函数一样丰富的身体。

这就是说,Lua影响了我的编程风格,广泛使用了匿名函数,并且把代码与他们混淆了。 最重要的是,我倾向于将map / reduce看作是抽象运算符,而不考虑列表parsing或生成器,几乎就像我使用这些运算符明确推迟实现决定一样。

编辑:这是一个很老的问题,我对这件事的看法有所改变。

首先,我强烈反对将lambdaexpression式分配给一个variables; 因为Python有一个特殊的语法(提示, def )。 除此之外,lambda的许多用途,即使没有得到名字,也有预定义的(和更高效的)实现。 例如,所讨论的例子可以缩写为(1).__add__ ,而不需要将其包含在lambdadefoperatoritertoolsfunctools模块的一些组合可以满足其他许多常见的用途。

我同意nosklo。 顺便说一句,即使有一次使用,扔掉function,大部分时间你只是想使用操作模块的东西。

EG:

你有这个签名的函数:myFunction(数据,callback函数)。

你想传递一个添加2个元素的函数。

使用lambda:

 myFunction(data, (lambda x, y : x + y)) 

pythonic方式:

 import operator myFunction(data, operator.add) 

当然,这是一个简单的例子,但是运营商模块提供了很多东西,包括列表和字典的设置器/获取器。 真的很酷。

如果你只是将lambda分配给本地范围内的一个variables,那么你可以使用def,因为它更具可读性,将来可以更容易地扩展:

 fun = lambda a, b: a ** b # a pointless use of lambda map(fun, someList) 

要么

 def fun(a, b): return a ** b # more readable map(fun, someList) 

lambda有用于生成新的函数:

 def somefunc(x): return lambda y: x+y f = somefunc(10) f(2) >>> 12 f(4) >>> 14 

主要区别在于你不能使用内联def函数,这在我看来是lambda函数最方便的用例。 例如,sorting对象列表时:

 my_list.sort(key=lambda o: ox) 

因此,我build议保持lambda的使用这种平凡的操作,这也没有真正受益于命名该函数提供的自动文档。