我正在试图找出Python lambdas。 lambda是现实生活中应该被遗忘的“有趣”语言项目之一吗?
我确信有一些可能需要它的边缘情况,但考虑到它的模糊性,它在将来版本中重新定义的可能性(我基于它的各种定义的假设)和降低的编码清晰度 - 应该避免吗?
这让我想起C类型的溢出(缓冲区溢出) - 指向顶部变量并重载以设置其他字段值。感觉就像是一种技术表演,但维护编码器的噩梦。
答案 0 :(得分:956)
你在谈论lambda functions吗?像
lambda x: x**2 + 2*x - 5
这些东西实际上非常有用。 Python支持一种称为函数式编程的编程风格,您可以将函数传递给其他函数来执行操作。例如:
mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])
将mult3
设置为[3, 6, 9]
,原始列表中的那些元素是3的倍数。这比
def filterfunc(x):
return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])
当然,在这种特殊情况下,你可以做与列表理解相同的事情:
mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]
(或者甚至是range(3,10,3)
),但是还有许多其他更复杂的用例,你不能使用列表理解,lambda函数可能是写出来的最短方法。
从其他函数返回函数
>>> def transform(n):
... return lambda x: x + n
...
>>> f = transform(3)
>>> f(4)
7
这通常用于创建函数包装器,例如Python的装饰器。
将可迭代序列的元素与reduce()
>>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
'1, 2, 3, 4, 5, 6, 7, 8, 9'
按备用键排序
>>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
[5, 4, 6, 3, 7, 2, 8, 1, 9]
我经常使用lambda函数。我花了一段时间才习惯他们,但最终我开始明白他们是这种语言非常有价值的一部分。
答案 1 :(得分:354)
lambda
只是一种说function
的奇特方式。除了它的名字,它没有任何模糊,令人生畏或神秘的东西。当您阅读以下内容时,请在脑海中将lambda
替换为function
:
>>> f = lambda x: x + 1
>>> f(3)
4
它只定义了x
的函数。其他一些语言,如R
,明确地说:
> f = function(x) { x + 1 }
> f(3)
4
你知道吗?这是编程中最自然的事情之一。
答案 2 :(得分:102)
两行摘要:
lambda
关键字:不必要,偶尔有用。如果你发现自己做了任何远程复杂的事情,就把它拿走并定义一个真正的功能。答案 3 :(得分:72)
lambda是一个非常重要的抽象机制的一部分,它处理高阶函数。要正确理解其价值,请观看Abelson and Sussman的高质量课程,并阅读书籍SICP
这些是现代软件业务中的相关问题,并且越来越受欢迎。
答案 4 :(得分:56)
lambdas在GUI编程中非常有用。例如,假设您正在创建一组按钮,并且您希望使用单个参数化回调而不是每个按钮的唯一回调。 Lambda让您轻松实现这一目标:
for value in ["one","two","three"]:
b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
b.pack()
(注意:虽然此问题专门询问lambda
,但您也可以使用functools.partial获取相同类型的结果)
另一种方法是为每个按钮创建一个单独的回调,这可能会导致重复的代码。
答案 5 :(得分:56)
我怀疑lambda会消失。 请参阅Guido's post,了解最终放弃尝试删除它。另请参阅an outline of the conflict。
您可以查看此帖子,了解有关Python功能特性背后交易的更多历史记录: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html
奇怪的是,最初促使引入lambda和其他功能特性的map,filter和reduce函数在很大程度上已被列表推导和生成器表达式所取代。实际上,reduce函数已从Python 3.0中的内置函数列表中删除。 (但是,没有必要发送有关删除lambda,map或filter的投诉:他们会留下来。: - )
我自己的两分钱:就清晰度来说,很少有兰达值得。通常有一个更清晰的解决方案,不包括lambda。
答案 6 :(得分:36)
在Python中,lambda
只是一种定义内联函数的方法,
a = lambda x: x + 1
print a(1)
和..
def a(x): return x + 1
print a(1)
.. 完全相同。
没有什么可以用lambda做的,你不能用常规函数做 - 在Python函数中就像其他任何东西一样对象,而lambdas只是定义一个函数:
>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>
老实说,我认为lambda
关键字在Python中是多余的 - 我从来没有需要使用它们(或者看到一个常用函数,列表解析或许多内置函数之一可能有的用法)反而更好地使用了)
有关完全随机的示例,请参阅文章"Python’s lambda is broken!":
要了解lambda是如何被破坏的,请尝试生成一个函数列表
fs=[f0,...,f9]
,其中fi(n)=i+n
。第一次尝试:>>> fs = [(lambda n: i + n) for i in range(10)] >>> fs[3](4) 13
我认为,即使这确实有效,但它是可怕的和“非语音”的,同样的功能可以用无数其他方式编写,例如:
>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
是的,它不一样,但我从不看到了需要在列表中生成一组lambda函数的原因。它可能在其他语言中有意义,但Python不是Haskell(或Lisp,或......)
请注意我们可以使用lambda并仍然达到预期的效果 结果就是这样:
>>> fs = [(lambda n,i=i: i + n) for i in range(10)] >>> fs[3](4) 7
编辑:
有少数情况下lambda很有用,例如在PyQt应用程序中连接信号时通常很方便,如下所示:
w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())
执行w.textChanged.connect(dothing)
只会使用额外的dothing
参数调用event
方法并导致错误。使用lambda意味着我们可以整齐地删除参数而无需定义包装函数。
答案 7 :(得分:29)
我发现lambda对于执行相同操作的函数列表很有用,但是对于不同的情况。与Mozilla plural rules一样。
plural_rules = [
lambda n: 'all',
lambda n: 'singular' if n == 1 else 'plural',
lambda n: 'singular' if 0 <= n <= 1 else 'plural',
...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'
如果你必须为所有那些定义一个函数,你会在它结束时发疯。对plural_rule_1
,plural_rule_2
等函数名称也不太好。当你依赖于变量函数id时,你需要eval()
。
答案 8 :(得分:26)
使用lambda
可以做的任何事情都可以使用命名函数或列表和生成器表达式做得更好。
因此,在大多数情况下,你应该只是其中一个基本上在任何情况下(除了在交互式解释器中编写的临时代码)。
答案 9 :(得分:19)
我已经使用Python几年了,我从来没有遇到过我需要 lambda的情况。实际上,正如tutorial所述,它仅仅是语法糖。
答案 10 :(得分:17)
Lambda函数它是一种创建函数的非官僚方式。
就是这样。例如,让我们假设您拥有主要功能并需要平方值。让我们看看传统方式和lambda方法:
传统方式:
def main():
...
...
y = square(some_number)
...
return something
def square(x):
return x**2
lambda方式:
def main():
...
square = lambda x: x**2
y = square(some_number)
return something
看到区别?
Lambda函数非常适合列表,例如列表推导或映射。事实上,列表理解它是一种使用lambda表达自己的“pythonic”方式。例如:
>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]
让我们看看语法的每个元素意味着什么:
[]:“给我一个清单”
x ** 2:“使用这个新生的函数”
对于a中的x:“进入”
中的每个元素
那很方便呃?创建这样的功能。让我们用lambda重写它:
>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]
现在让我们使用map,这是一回事,但更加语言中立。地图有两个参数:
(i)一个功能
(ii)可迭代的
并给出一个列表,其中每个元素都是函数应用于iterable的每个元素。
所以,使用地图我们会:
>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)
如果掌握了lambdas和映射,那么您将拥有以简洁的方式操纵数据的强大功能。 Lambda函数既不模糊也不带走代码清晰度。不要把事情与新事物混淆。一旦你开始使用它们,你会发现它非常清楚。
答案 11 :(得分:17)
我不能说python的lambda的特定实现,但一般来说lambda函数非常方便。它们是函数式编程的核心技术(甚至是技术),它们在面向对象程序中也非常有用。对于某些类型的问题,它们是最好的解决方案,所以当然不应该忘记!
我建议您阅读closures和map function(链接到python文档,但它几乎存在于支持功能构造的所有语言中),以了解它为什么有用。
答案 12 :(得分:13)
我认为低估lambda
的一个好处就是它推迟了对简单形式的评估,直到需要价值为止。让我解释。
实现了许多库例程,因此它们允许某些参数为callables(lambda为1)。我们的想法是,实际值只会在它被使用时计算(而不是在它被调用时)。一个(人为的)例子可能有助于说明这一点。假设您有一个例程,它将记录给定的时间戳。您希望例程使用当前时间减去30分钟。你会这样称呼它
log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))
现在假设只有在某个事件发生时才会调用实际函数,并且您希望仅在此时计算时间戳。你可以这样做
log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))
假设log_timestamp
可以处理这样的可调用对象,它会在需要时对其进行评估,并且您将获得当时的时间戳。
当然有其他方法可以做到这一点(例如使用operator
模块),但我希望我已经传达了这一点。
更新:Here是一个更具体的现实世界示例。
更新2 :我认为这是所谓的thunk的一个例子。
答案 13 :(得分:11)
如上所述,Python中的lambda运算符定义了一个匿名函数,而Python函数则是闭包。重要的是不要将闭包的概念与运算符lambda混淆,运算符lambda只是它们的语法美沙酮。
几年前,当我开始使用Python时,我经常使用lambdas,认为它们很酷,还有列表推导。但是,我写了并且必须维护一个用Python编写的大型网站,大约有几千个功能点。我从经验中学到了lambda可以用原型进行原型设计,但除了保存一些关键的stokes,有时候没有提供内联函数(命名闭包)之外什么都不提供。
基本上归结为几点:
这足以使它们四舍五入并将它们转换为命名闭包。但是,我对匿名关闭还有另外两个怨恨。
第一个怨恨只是他们只是另一个不必要的关键词,使语言变得混乱。
第二个怨恨是更深层次和范式层面,即我不喜欢它们促进功能编程风格,因为这种风格不如消息传递,面向对象或程序风格灵活,因为lambda演算是不是Turing-complete(幸运的是,在Python中,即使在lambda中,我们仍然可以摆脱这种限制)。我觉得lambdas推广这种风格的原因是:
有一个隐含的回报,即它们似乎应该是“功能”。
它们是另一种更明确,更易读,更可重用且更通用的机制的替代状态隐藏机制:方法。
我努力编写没有lambda的Python,并在视线中删除lambdas。我认为如果没有lambda,Python会是一种稍微好一点的语言,但这只是我的观点。
答案 14 :(得分:11)
Lambdas实际上是非常强大的构造,源于函数式编程中的思想,并且在Python的不久的将来它决不会被轻易修改,重新定义或删除。它们可以帮助您编写更强大的代码,因为它允许您将函数作为参数传递,从而将函数的概念视为一等公民。
Lambdas确实会让人感到困惑,但是一旦获得了可靠的理解,你就可以写出这样干净优雅的代码:
squared = map(lambda x: x*x, [1, 2, 3, 4, 5])
上面的代码行返回列表中数字的方块列表。当然,你也可以这样做:
def square(x):
return x*x
squared = map(square, [1, 2, 3, 4, 5])
很明显,以前的代码更短,如果您打算在一个地方使用map函数(或任何类似的函数作为参数),尤其如此。这也使代码更直观和优雅。
另外,正如@David Zaslavsky在他的回答中提到的那样,列表推导并不总是那样,特别是如果你的列表必须从一些模糊的数学方式中获取值。
从更实际的角度来看,lambdas最近的一大优势是GUI和事件驱动编程。如果你看一下Tkinter中的回调,它们作为参数的所有内容都是触发它们的事件。 E.g。
def define_bindings(widget):
widget.bind("<Button-1>", do-something-cool)
def do-something-cool(event):
#Your code to execute on the event trigger
现在如果你有一些参数传递怎么办?像传递2个参数来存储鼠标单击的坐标一样简单。你可以这样轻松地做到这一点:
def main():
# define widgets and other imp stuff
x, y = None, None
widget.bind("<Button-1>", lambda event: do-something-cool(x, y))
def do-something-cool(event, x, y):
x = event.x
y = event.y
#Do other cool stuff
现在你可以说这可以使用全局变量来完成,但是你真的想要担心内存管理和泄漏,特别是如果全局变量只在一个特定的地方使用吗?那将是糟糕的编程风格。
简而言之,lambdas很棒,永远不应该被低估。虽然Python lambdas与LISP lambdas不同(它们更强大),但是你可以用它们做很多神奇的事情。
答案 15 :(得分:8)
Lambda与一般的函数式编程风格密切相关。通过将函数应用于某些数据并合并结果来解决问题的想法是谷歌用来实现其大多数算法的。
以函数式编程风格编写的程序很容易并行化,因此对于现代多核机器而言变得越来越重要。 所以总之,不,你不应该忘记它们。
答案 16 :(得分:7)
首先祝贺设法找出lambda。在我看来,这是一个非常强大的构造。这些日子对功能性编程语言的趋势肯定是一个指标,它既不应该避免,也不会在不久的将来重新定义。
你只需要思考一点点不同。我很快你会相信它。但是如果你只处理python,要小心。因为lambda不是真正的闭包,它以某种方式被“破坏”:pythons lambda is broken
答案 17 :(得分:6)
我使用lambdas来避免代码重复。这将使该功能易于理解 例如:
def a_func()
...
if some_conditon:
...
call_some_big_func(arg1, arg2, arg3, arg4...)
else
...
call_some_big_func(arg1, arg2, arg3, arg4...)
我将其替换为临时lambda
def a_func()
...
call_big_f = lambda args_that_change: call_some_big_func(arg1, arg2, arg3, args_that_change)
if some_conditon:
...
call_big_f(argX)
else
...
call_big_f(argY)
答案 18 :(得分:5)
我是一个python初学者,所以为了清楚地了解lambda,我将它与'for'循环进行了比较;在效率方面。 这是代码(python 2.7) -
import time
start = time.time() # Measure the time taken for execution
def first():
squares = map(lambda x: x**2, range(10))
# ^ Lambda
end = time.time()
elapsed = end - start
print elapsed + ' seconds'
return elapsed # gives 0.0 seconds
def second():
lst = []
for i in range(10):
lst.append(i**2)
# ^ a 'for' loop
end = time.time()
elapsed = end - start
print elapsed + ' seconds'
return elapsed # gives 0.0019998550415 seconds.
print abs(second() - first()) # Gives 0.0019998550415 seconds!(duh)
答案 19 :(得分:5)
我刚刚开始使用Python并首先进入Lambda-我花了一些时间才弄明白。
请注意,这不是对任何事情的谴责。每个人都有一套不容易的事情。
lambda是否应该忘记现实生活中那些“有趣”的语言项目?
没有
我确信有一些可能需要它的边缘情况,但考虑到它的含糊不清,
这并不模糊。在我过去的两个团队中,每个人都在使用这个功能。
在未来版本中重新定义它的潜力(我基于其各种定义的假设)
除了几年前修复闭包语义之外,我没有看到过在Python中重新定义它的严肃建议。
和降低的编码清晰度 - 应该避免吗?
如果你正确使用它,那就不那么清楚了。相反,有更多的语言结构可以提高的清晰度。
这让我想起了C类型的溢出(缓冲区溢出) - 指向顶部变量并重载以设置其他字段值...一种技术表演但是维护编码器的噩梦......
Lambda就像缓冲区溢出一样?哇。如果你认为这是一个“维护噩梦”,我无法想象你如何使用lambda。
答案 20 :(得分:5)
使用lambdas的一个有用的例子是提高长列表推导的可读性。
在此示例中,loop_dic
是为了清晰起见,但想象loop_dic
非常长。如果您只使用包含i
的普通值而不是该值的lambda版本,则会获得NameError
。
>>> lis = [{"name": "Peter"}, {"name": "Josef"}]
>>> loop_dic = lambda i: {"name": i["name"] + " Wallace" }
>>> new_lis = [loop_dic(i) for i in lis]
>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]
而不是
>>> lis = [{"name": "Peter"}, {"name": "Josef"}]
>>> new_lis = [{"name": i["name"] + " Wallace"} for i in lis]
>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]
答案 21 :(得分:5)
我可以举个例子,我实际上需要lambda认真。我正在制作一个图形程序,使用右键单击文件并为其分配三个选项之一。事实证明,在Tkinter(GUI接口程序,我正在写这个),当有人按下按钮时,它不能被分配给接受参数的命令。因此,如果我选择其中一个选项并希望我选择的结果是:
print 'hi there'
然后没什么大不了的。但是如果我需要我的选择来获得特定的细节呢?例如,如果我选择选择A,它会调用一个函数,该函数接受一些依赖于选择A,B或C的参数,TKinter不支持这一点。 Lamda是实际解决这个问题的唯一选择......
答案 22 :(得分:5)
我今天开始阅读David Mertz的书“Python中的文本处理”。虽然他对Lambda的描述相当简洁,但第一章中的例子与附录A中的解释相结合,使得它们(最后)跳出了页面,突然间我理解了它们的价值。这并不是说他的解释对你有用,我仍处于发现阶段,所以除了以下内容之外,我不会尝试添加这些答案: 我是Python的新手 我是OOP的新手 Lambdas对我来说是一场斗争 现在我读了Mertz,我想我得到了它们,我认为它们非常有用,因为我认为它们允许更清晰的编程方法。
他再现了Python的Zen,其中一行是 Simple比复杂更好。作为非OOP程序员阅读lambdas代码(直到上周列表理解)我认为 - 这很简单?。我终于意识到,实际上这些功能使得代码比替代方案更具可读性和可理解性 - 它总是某种循环。我也意识到像财务报表一样 - Python不是为新手用户设计的,而是专为想要接受教育的用户而设计的。我无法相信这种语言有多强大。当我突然意识到lambdas的目的和价值时,我想要撕掉大约30个程序,并在适当的时候重新开始使用lambda。
答案 23 :(得分:4)
我使用lambda
创建包含参数的回调。在一行中写一个lambda比写一个方法来执行相同的功能更清晰。
例如:
import imported.module
def func():
return lambda: imported.module.method("foo", "bar")
而不是:
import imported.module
def func():
def cb():
return imported.module.method("foo", "bar")
return cb
答案 24 :(得分:4)
我经常使用它,主要用作null object或将参数部分绑定到函数。
以下是示例:
{
DATA_PACKET: self.handle_data_packets
NET_PACKET: self.handle_hardware_packets
}.get(packet_type, lambda x : None)(payload)
假设我有以下API
def dump_hex(file, var)
# some code
pass
class X(object):
#...
def packet_received(data):
# some kind of preprocessing
self.callback(data)
#...
然后,当我不想快速将收到的数据转储到文件时,我就这样做了:
dump_file = file('hex_dump.txt','w')
X.callback = lambda (x): dump_hex(dump_file, x)
...
dump_file.close()
答案 25 :(得分:2)
Lambda是一个过程构造函数。你可以在运行时合成程序,虽然Python的lambda不是很强大。请注意,很少有人理解这种编程。