为什么要使用lambda函数?


74

我可以找到很多东西,向我展示什么是lambda函数,以及语法如何工作以及什么不是。但是除了“凉爽因素”(我可以在中间调用另一个函数,整洁!)之外,我还没有看到任何令人信服的东西来说明为什么我真的需要/想要使用它们。

在我所看到的大多数示例中,这似乎更多是一种风格或结构选择。并且kinda打破了python规则中的“唯一正确的做事方式”。它如何使我的程序更正确,更可靠,更快或更易于理解?(我见过的大多数编码标准都倾向于告诉您避免在一行上写过分复杂的语句。如果这样更易于阅读,请将其分解。)


命令式编程语言中的接口或功能/方法签名不只是功能性编程的对应物吗?(->用于指定回调,从而允许人们创建松耦合的应用程序/软件组件。)
Javaguru,2010年

Lambda是“函数文字”。出于列表和地图文字有用的原因(与手动执行相反),它们是有用且方便的append。如果在某些情况下允许一个,则在任何情况下都没有理由反对另一个。
帕维尔米纳夫


1
这回答了你的问题了吗?为什么Python Lambda有用?
乔什·科雷亚

Answers:


34

这是一个很好的例子:

def key(x):
    return x[1]

a = [(1, 2), (3, 1), (5, 10), (11, -3)]
a.sort(key=key)

a = [(1, 2), (3, 1), (5, 10), (11, -3)]
a.sort(key=lambda x: x[1])

从另一个角度来看:Lambda表达式也被称为“匿名函数”,并且在某些编程范例(尤其是函数编程)中非常有用,lambda演算为其提供了灵感。

http://en.wikipedia.org/wiki/Lambda_calculus


8
无关:您可以使用operator.itemgetter(1)代替lambda x: x[1]
jfs

1
@JF Sebastian:虽然需要您import operator先。@琥珀:谢谢;我不记得我的头顶了,所以只是在谨慎方面犯了错误。
JAB

4
@JF Sebastian,是的,“ operator.itemgetter”,以及数百种其他短函数,每个人对于一个特定的用途都必须心地知道-或使用lambda,其中一个人可以就地创建通用表达式,而不必准确回忆起哪个简短功能可以完成这项工作。 正如OP所要求的那样,使用operator.itemgetter似乎可以很好地证明lambda是合理的。
jsbueno

2
operator实际上,其中的功能比其lambda的功能快一百倍。
Jochen Ritzel

1
@NoMore:直到您遇到一些更复杂的事情为止,例如lambda x: x[0]**2 + x[1]**2
kennytm 2010年

18

在某些情况下,尤其是在与mapet al的交易中,语法更加简洁。

map(lambda x: x * 2, [1,2,3,4])

在我看来比以下更好:

def double(x):
    return x * 2

map(double, [1,2,3,4])

我认为在这种情况下,lambda是一个更好的选择,因为它def double似乎与map使用它的人几乎脱节了。另外,我猜它还有一个额外的好处,就是当您完成该功能后,该函数将被丢弃。

我认为,lambda有一个缺点,限制了它在Python中的用途:lambda只能有一个表达式(即,不能有多行)。它只是不能在强制使用空格的语言中工作。

另外,每当我使用lambda时,我都会感觉很棒。


11
在这种情况下,列表理解可能更适合[x*2 for x in [1,2,3,4]]
jfs

1
我不了解python(尽管在我的学习列表中绝对很高),所以我想知道...确实有很好的理由不允许多行lambda表达式吗?为什么lambda表达式的主体不能只是右边的一个标签或其他内容?
凸轮

4
Guido关于多行lambda以及其他内容的博客文章:artima.com/weblogs/viewpost.jsp?thread=147358
唐纳德·迈纳

2
@incrediman-在这一点上,lambda与函数之间没有区别-函数仍然是可以按名称引用的对象,具有多行lambda将是def。
马修·J·莫里森

4
map((2).__mul__, [1,2,3,4])
kennytm

12

Lambda函数在诸如回调函数之类的地方或需要使用一次性函数的地方最为有用。JAB的示例非常完美-最好与关键字参数一起使用key,但它仍提供有用的信息。

什么时候

def key(x):
    return x[1]

距离出现300行

[(1,2), (3,1), (5,10), (11,-3)].sort(key)

钥匙有什么作用?确实没有迹象。您可能会有某种猜测,尤其是如果您熟悉该功能时,但通常需要回头看看。太太

[(1,2), (3,1), (5,10), (11,-3)].sort(lambda x: x[1])

告诉你更多。

  1. 排序将函数作为参数
  2. 该函数采用1个参数(并“返回”结果)
  3. 我正在尝试按列表中每个元素的第二个值对列表进行排序
  4. (如果列表是变量,那么您将看不到值),此逻辑希望列表中至少包含2个元素。

可能还有更多的信息,但是仅使用匿名lambda函数而不是命名函数,您已经获得了巨大的信息。

另外,它不会污染您的名称空间;)


我最初的示例并不十分完美,因为在Python 3中,您必须使用key作为关键字参数(如果key=省略,则会引发TypeError )。我也忘记了sort,它执行就地排序,实际上并没有返回它排序的对象,因此您必须在已经分配给变量的可变序列上使用它。
JAB

错误,您无法直接通过函数进行此类排序,您需要使用sort(key = key)或sort(key = lambda函数)
DevC

这段代码在python 2(第一个参数是cmp,不是key)和python 3(其中sort不接受任何位置参数)中都被破坏了。在这两种情况下,您都需要使用...sort(key=...)
6502

11

对我来说,这与代码的表现力有关。在编写人们必须支持的代码时,该代码应尽可能简洁明了地讲述一个故事。有时,lambda表达式更复杂,而有时更直接地告诉代码行或代码块在做什么。写作时要运用判断力。

认为它就像构造一个句子。重要的部分是什么(名词和动词与对象和方法等),以及对于该行代码段,应该如何对它们进行排序,以直观地传达其功能。


2
真是太好了:“代码应该尽可能简洁明了地讲一个故事……把它想像成一个句子……”-我将在下一门课程中使用它,如果你不在乎!
桑杰·马诺哈

7

是的,您是对的-这是结构性选择。仅使用lambda表达式可能不会使您的程序更正确。也没有使它们更可靠,这与速度无关。

这仅与灵活性和表达能力有关。喜欢列表理解。您可以完成大多数定义命名函数的操作(可能会污染名称空间,但这又纯粹是样式问题)。

它可以帮助您提高可读性,因为您不必定义单独的命名函数,其他人必须查找,阅读和理解它所做的只是在其参数上调用方法blah()。

当您使用它编写用于创建和返回其他函数的函数时,可能会更加有趣,这些函数的确切功能取决于其参数。这可能是一种非常简洁易读的参数化代码行为的方式。您可以表达更多有趣的想法。

但这仍然是结构性选择。否则,您可以这样做。但是面向对象编程也是如此;)


6

暂时忽略一下我们正在谈论的具体为匿名函数的细节。函数(包括匿名函数)在Python中是可分配的数量(几乎但不是真正的值)。像这样的表达

map(lambda y: y * -1, range(0, 10))

明确提到四个匿名数量:-1、0、10和lambda运算符的结果,以及map调用的隐式结果。可以使用某些语言创建匿名类型的值。因此,请忽略函数和数字之间的表面区别。何时使用匿名函数而不是命名函数的问题类似于何时在代码中放置裸数字文字以及何时声明TIMES_I_WISHED_I_HAD_A_PONY或的问题。BUFFER_SIZE。有时适合使用(数字,字符串或函数)文字,有时更适合使用此类名称命名并通过其名称进行引用。

见。艾伦·霍鲁布(Allen Holub)关于Java设计模式的富有启发性,发人深省的书;他使用了很多匿名类。


1
这是一个很好的答案。与仅提供示例相反。并不是这些示例对于理解lambda函数何时有用很有帮助。
AVProgrammer 2012年

5

Lambda虽然在某些情况下很有用,但很容易被滥用。lambda几乎总是使代码更难阅读。尽管将所有代码都放在一行中可能会让人满意,但它会吸引下一个必须阅读您的代码的人。

直接来自PEP8

“ Guido的主要见解之一是代码的读取次数比编写的次数要多。”


2

我已经学习过的lambda函数的一种用法,在哪里没有其他好的替代方法,或者至少在我看来是最好的,它是作为函数参数中的默认操作

parameter=lambda x: x

这将返回不变的值,但是您可以选择提供一个函数来执行转换或操作(例如打印答案,不仅返回)

通常,将排序用作键也很有用:

key=lambda x: x[field]

效果是按顺序对每个项目的fieldth(基于零的记忆)元素进行排序。对于反转,您不需要lambda,因为它更易于使用

reverse=True

通常,执行新的实函数并使用它代替lambda几乎一样容易。如果人们研究了很多Lisp或其他函数式编程,他们也自然会使用lambda函数,因为在Lisp中,函数定义是由lambda演算处理的。


2

Lambda是对象,而不是方法,并且不能以与方法相同的方式调用它们。例如

succ = ->(x){ x+1 }

succ mow包含一个Proc对象,我们可以像其他对象一样使用它:

succ.call(2)

给我们输出= 3


1
OP特别提到了python lambdas。这些是红宝石lambda。
2upmedia 2015年

1

我想指出一种情况,除了列表处理之外,lambda函数似乎是最佳选择:

from tkinter import *
from tkinter import ttk        
def callback(arg):
    print(arg)
    pass
root = Tk()
ttk.Button(root, text = 'Button1', command = lambda: callback('Button 1 clicked')).pack()
root.mainloop()

而且,如果我们在这里放下lambda函数,则该回调可能只执行一次回调。

ttk.Button(root, text = 'Button1', command = callback('Button1 clicked')).pack()

1

另一点是python没有switch语句。将lambda与dicts结合可以是一种有效的选择。例如:

switch = {
 '1': lambda x: x+1, 
 '2': lambda x: x+2,
 '3': lambda x: x+3
}

x = starting_val
ans = expression
new_ans = switch[ans](x)

1

Lambda是匿名函数(无名称的函数),可以分配给变量,也可以作为参数传递给另一个函数。当您需要一小段功能可以同时运行一次或仅运行一次时,lambda就会有用。除了在全局范围内编写函数或将其包含在主程序中之外,您还可以在需要时将几行代码扔给变量或其他函数。同样,当您在函数调用期间将函数作为参数传递给另一个函数时,可以更改参数(匿名函数)以使函数本身具有动态性。假设匿名函数在其作用域之外使用变量,则称为闭包。这在回调函数中很有用。


0

在某些情况下,将简单的东西表示为lambda更为清晰。考虑常规排序与反向排序,例如:

some_list = [2, 1, 3]
print sorted(some_list)
print sorted(some_list, lambda a, b: -cmp(a, b))

对于后一种情况,编写单独的完整函数以返回a-cmp(a, b)会比lambda产生更多的误解。


3
无关:您可以使用sorted(..., reverse=True)sorted(..., lambda a,b: cmp(b,a))
jfs

绝对不是无关的,而且比答案所暗示的要容易理解得多。
KevLoughrey

请考虑问题和答案的年龄。那时,我在Python方面的重要经验来自Python 2.3时代,价格为$ {reasons},在2.4中添加了反向参数(和排序函数)。
方丈

0

确实,滥用lambda函数通常会导致错误且难以阅读的代码。另一方面,如果正确使用它,则相反。这个线程中已经有了不错的答案,但是我遇到的一个例子是:

def power(n):
    return lambda x: x**n

square = power(2)
cubic = power(3)
quadruple = power(4)

print(square(10)) # 100
print(cubic(10)) # 1000
print(quadruple(10)) # 10000

无需使用lambda,可以通过许多其他方式重写此简化的案例。仍然可以通过此示例推断出lambda函数如何在可能更复杂的情况和函数中提高可读性和代码重用。


-1

您掌握了lambda,您掌握了python中的快捷方式,这是为什么:

data=[(lambda x:x.text)(x.extract())  for x in soup.findAll('p') ]
                  ^1           ^2         ^3           ^4

在这里,我们可以看到列表理解的4个部分:

  • 1:我终于想要这个
  • 2:x.extract将对x执行一些操作,此处它会从汤中弹出元素
  • 3:x是可迭代的列表,它与提取操作一起传递给lambda的输入(在2处)
  • 4:一些列表

我没有发现在lambda中使用2条语句的其他方法,但是通过这种管道内衬,我们可以利用lambda的无限潜力。

编辑:正如juanpa在评论中指出的那样,使用x.extract()。text完全可以,但是重点是解释了lambda管道的使用,即将lambda1的输出作为输入传递给lambda2。通过(lambda1 y:g(x))(lambda2 x:f(x))


这是荒谬的。您应该这样做x.extract().text
juanpa.arrivillaga

我想到了,x.extract().text()但重点是要解释“ lambda Pipe”。因为并非所有类都具有可以返回属性副本的方法。BS4可以选择这样做,但是通常不提供这种功能。
nikhil swami

-2

Lambda允许您即时创建函数。我见过的大多数示例除了创建具有在创建时传递的参数(而不是执行)的函数外,所做的工作不多。或者他们通过不需要在使用前正式声明功能来简化代码。

一个更有趣的用途是动态构造python函数,以评估直到运行时(用户输入)才知道的数学表达式。创建函数后,可以使用不同的参数重复调用该函数以评估表达式(例如您想绘制它)。给定eval(),这甚至可能是一个糟糕的例子。这种使用方式是“真正”力量的所在-动态创建更复杂的代码,而不是您经常看到的简单示例,这些示例只不过是减少(源)代码大小而已。


6
Lambda不允许您执行普通函数定义不能同样出色地执行的任何操作。就像其他答案所说的那样,您可能更喜欢lambda,因为它可以使代码更清晰,但是普通的“ def”与lambda一样动态。
邓肯

不,先生,不一样。您可以定义一个函数来计算x + 1,也可以使用lambda创建一个函数来计算x + n并将1传入n。您还可以使用相同的lambda创建一堆返回x加不同值的函数。关键是部分功能是在运行时以普通def无法完成的方式确定的。每个人似乎都认为这是一个不错的速记,可以真正做得更多。
phkahler
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.