为什么要使用lambda函数?

时间:2010-07-15 19:41:55

标签: python lambda

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

在我见过的大多数例子中,它似乎更像是一种风格或结构选择。并且有点打破了python规则中的“只有一种正确的做法”。它如何使我的程序更正确,更可靠,更快速或更容易理解? (我见过的大多数编码标准都倾向于告诉你在单行上避免过于复杂的语句。如果它更易于阅读,则将其分解。)

16 个答案:

答案 0 :(得分:27)

这是一个很好的例子:

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

答案 1 :(得分:16)

在某些情况下,语法更简洁,主要是在处理map等等时。

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中的用处,在我看来:lambdas只能有一个表达式(即你不能有多行)。它只能用于强制空格的语言。

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

答案 2 :(得分:9)

Lambda函数在回调函数或需要一次性函数的地方最有用。 JAB的例子很完美 - 最好伴随关键字参数key,但它仍然提供有用的信息。

def key(x):
    return x[1]

距离

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

关键是做什么的?真的没有任何迹象。您可能会有某种猜测,特别是如果您熟悉该功能,但通常需要回头看。 OTOH,

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

告诉你更多。

  1. Sort将函数作为参数
  2. 该函数需要1个参数(并“返回”结果)
  3. 我正在尝试按列表中每个元素的第二个值对此列表进行排序
  4. (如果列表是变量,因此您无法看到值),此逻辑要求列表中至少包含2个元素。
  5. 可能还有更多信息,但是通过使用匿名lambda函数而不是命名函数,你已经获得了大量信息。

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

答案 3 :(得分:7)

对我而言,这是代码表现力的问题。在编写人们必须支持的代码时,该代码应该以尽可能简洁易懂的方式讲述故事。有时lambda表达式更复杂,有时它更直接地告诉代码行或代码块在做什么。写作时要慎重。

把它想象成一个句子。什么是重要的部分(名词和动词与对象和方法等),以及如何为该行或代码块排序,以便直观地传达它的作用。

答案 4 :(得分:5)

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

这只是关于灵活性和表达力。喜欢列表理解。您可以执行大部分定义命名函数(可能会污染命名空间,但这又是纯粹的风格问题)。

它可以帮助实现可读性,你无需定义一个单独的命名函数,其他人必须查找,阅读和理解它所做的就是在其参数上调用方法blah()

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

但这仍然是一种结构性选择。你可以这样做。但是面向对象编程也是如此;)

答案 5 :(得分:5)

暂时忽略我们正在谈论的具体匿名功能的详细信息。函数(包括匿名函数)在Python中是可分配的数量(几乎,但不是真正的值)。一个像

这样的表达式
map(lambda y: y * -1, range(0, 10))

明确提到四个匿名量:-1,0,10和lambda运算符的结果,加上map调用的隐含结果。在某些语言中可以创建匿名类型的。所以忽略功能和数字之间的表面差异。何时使用匿名函数而不是命名函数的问题类似于何时在代码中放置裸数字文字以及何时事先声明TIMES_I_WISHED_I_HAD_A_PONYBUFFER_SIZE的问题。有时候使用(数字,字符串或函数)文字是合适的,有时候命名这样的东西并通过它的名称引用它更合适。

见例如。艾伦·霍鲁布(Allen Holub)关于Java设计模式的挑衅,思想或愤怒的书;他使用匿名课程。

答案 6 :(得分:2)

我学过的lambda函数的一个用法,以及其他不是很好的替代方案或至少最适合我的方法是函数参数中的默认操作

parameter=lambda x: x

这会返回没有更改的值,但您可以选择提供一个函数来执行转换或操作(比如打印答案,而不仅仅是返回)

通常,在排序中使用它是很有用的:

key=lambda x: x[field]

效果是按顺序对每个项目的fieldth(从零开始记忆)元素进行排序。对于倒车,你不需要lambda,因为它更清晰使用

reverse=True

通常,新的实际功能几乎同样容易,而不是使用lambda。如果人们研究了很多Lisp或其他函数式编程,他们也有使用lambda函数的自然倾向,就像在Lisp中一样,函数定义由lambda演算处理。

答案 7 :(得分:2)

Lambda虽然在某些情况下很有用,却有很大的滥用可能性。 lambda几乎总是让代码更难以阅读。虽然将所有代码整合到一行可能会令人满意,但是对于必须阅读代码的下一个人来说会很糟糕。

直接来自PEP8

“Guido的一个重要见解是,代码的阅读频率远高于编写代码。”

答案 8 :(得分:2)

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

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

succ mow拥有一个Proc对象,我们可以像其他任何一样使用它:

succ.call(2)

给我们一个输出= 3

答案 9 :(得分:1)

在某些情况下,将一些简单的东西表达为lambda要清楚得多。考虑常规排序与反向排序,例如:

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

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

答案 10 :(得分:1)

我想指出除list-processing之外的一种情况,其中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()

答案 11 :(得分:1)

另一点是python没有switch语句。将lambdas与dicts结合起来可能是一种有效的选择。 e.g:

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)

答案 12 :(得分:1)

Lambdas是匿名函数(没有名称的函数),可以分配给变量,也可以作为参数传递给另一个函数。当你需要一段时间或一次只运行一小段功能时,就会实现lambda的实用性。而不是在全局范围内编写函数或将其作为主程序的一部分包含在内,您可以在需要变量或其他函数时抛出几行代码。此外,当您在函数调用期间将函数作为参数传递给另一个函数时,您可以更改参数(匿名函数),使函数本身动态化。假设匿名函数使用其范围之外的变量,则称为闭包。这在回调函数中很有用。

答案 13 :(得分: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函数如何在可能更复杂的情况和函数中提高可读性和代码重用。

答案 14 :(得分:-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))

答案 15 :(得分:-2)

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

更有趣的用法是动态构造一个python函数来评估一个在运行时才知道的数学表达式(用户输入)。一旦创建,可以使用不同的参数重复调用该函数以评估表达式(假设您想绘制它)。鉴于eval(),这甚至可能是一个糟糕的例子。这种类型的使用是“真正的”功能 - 动态创建更复杂的代码,而不是您经常看到的简单示例,这些示例不仅仅是很好的(源)代码大小减少。