为什么Python lambda有用?
我试图找出Python lambda。 拉姆达是那些在现实生活中应该被遗忘的“有趣”的语言项目之一吗?
我确信有一些边缘情况可能需要,但是由于它的模糊性,它在未来版本中的重新定义的可能性(基于它的各种定义的我的假设)和降低的编码清晰度 – 是否应该被避免?
这让我想起了Ctypes溢出(缓冲区溢出) – 指向顶部variables和重载来设置其他字段值。 这感觉就像是一个技术人员的娴熟,但维修编码器的噩梦。
你在说lambda函数吗? 喜欢
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]
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函数可能是写出某些东西的最短path。
-
从另一个函数返回一个函数
>>> def transform(n): ... return lambda x: x + n ... >>> f = transform(3) >>> f(4) 7
这通常用于创build函数包装器,比如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'
-
按替代键sorting
>>> 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函数。 我花了一段时间去适应他们,但最终我明白,他们是语言中非常有价值的一部分。
lambda
只是说function
一种奇特的方式。 除了它的名字,没有什么模糊的,恐吓的或神秘的。 当你阅读下面的function
在你的脑海里用lambda
代替function
:
>>> f = lambda x: x + 1 >>> f(3) 4
它只是定义了一个x
的函数。 其他一些语言,比如R
,明确地说:
> f = function(x) { x + 1 } > f(3) 4
你看? 这是编程中最自然的事情之一。
双线总结:
- closures :非常有用。 学习他们,使用他们,爱他们。
- Python的
lambda
关键字:不必要,偶尔有用。 如果你发现自己做的任何事情都很复杂,那就把它拿出来,定义一个真正的function。
lambda是处理高阶函数的一个非常重要的抽象机制的一部分。 为了正确理解它的价值,请观看Abelson和Sussman的高质量课程,并阅读SICP
这些都是现代软件业务中的相关问题,并越来越受欢迎。
我怀疑拉姆达会消失。 看到圭多的post ,最后放弃尝试删除它。 也看到冲突的大纲 。
您可以查看这篇文章,了解有关Pythonfunction特性的更多历史logging: http : //python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html
奇怪的是,最初动机引入lambda和其他function特征的映射,过滤和减less函数在很大程度上被列表推导和生成器expression式所取代。 事实上,reduce函数已经从Python 3.0中的内build函数列表中删除了。 (但是,没有必要发送有关删除lambda,map或filter的投诉:他们正在停留。:-)
我自己的两分钱:只要清楚,lambda值得。 通常有一个更清晰的解决scheme,不包括lambda。
lambdas在GUI编程中非常有用。 例如,假设您正在创build一组button,并且您希望使用单个参数化callback,而不是每个button的唯一callback。 Lambda让你轻松完成:
for value in ["one","two","three"]: b = tk.Button(label=value, command=lambda arg=value: my_callback(arg)) b.pack()
(注意:虽然这个问题是专门询问lambda
,你也可以使用functools.partial来得到相同types的结果)
另一种方法是为每个button创build一个单独的callback,这会导致重复的代码。
在Python中, lambda
只是一种定义函数内联的方式,
a = lambda x: x + 1 print a(1)
和..
def a(x): return x + 1 print a(1)
.. 完全一样。
没有什么可以用lambda来做的,你不能用普通的函数来做 – 在Python中,函数和其他任何东西一样是一个对象,lambda简单地定义一个函数:
>>> a = lambda x: x + 1 >>> type(a) <type 'function'>
我真的认为lambda关键字在Python中是多余的 – 我从来没有需要使用它们(或者看到一个常用函数,列表理解或其中一个内置函数可以更好地使用)
对于一个完全随机的例子,从文章“Python的lambda被打破! :
要查看lambda是如何被破坏的,请尝试生成一个函数列表
fs=[f0,...,f9]
,其中fi(n)=i+n
。 第一次尝试:对于范围(10)中的i,fs = [(lambda:i + n)] fs3 13
我认为,即使这样做确实有效,它是非常可怕的,而且是“非音调的”,相同的function可以用无数其他方式来编写,例如:
>>> 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)
会调用带有额外event
参数的dothing
方法,并导致错误。使用lambda意味着我们可以完整地删除参数而不必定义一个包装函数
几乎任何你可以用lambda
做的事情,你可以用命名的函数或列表和生成器expression式做的更好。
因此,基本上在任何情况下(除了可能用交互式解释器编写的临时代码),大多数情况下你应该只是其中的一种。
我发现lambda对于做相同的函数列表是有用的,但对于不同的情况。 像Mozilla复数规则 。
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等函数名也不是很好。而当你依赖一个variables函数id的时候,你需要eval()。
我已经使用Python几年了,我从来没有遇到过需要 lambda的情况。 真的,正如教程所述,这只是语法糖。
Lambda函数是创build函数的非官僚方式。
而已。 举个例子,我们假设你有你的主要function,需要平方值。 让我们看看传统方式和lambda方式来做到这一点:
传统方式:
def main(): ... ... y = square(some_number) ... return something def square(x): return x**2
拉姆达方式:
def main(): ... square = lambda x: x**2 y = square(some_number) return something
看到不同?
Lambda函数与列表(如列表理解或映射)非常一致。 事实上,列表理解是使用lambdaexpression自己的“pythonic”方式。 例如:
>>>a = [1,2,3,4] >>>[x**2 for x in a] [1,4,9,16]
让我们来看看语法的每个元素是什么意思:
[]:“给我一个清单”
x ** 2:“使用这个新生function”
对于a中的x:“将每个元素放入一个”
这很方便吗? 像这样创build函数。 我们用lambda重写它:
>>> square = lambda x: x**2 >>> [square(s) for x in a] [1,4,9,16]
现在让我们使用map,这是一样的事情,但更多的语言中立。 地图有两个参数:
(i)一个function
(ii)可迭代的
并给你一个列表,其中每个元素是函数应用于每个元素的迭代。
所以,使用地图我们会有:
>>> a = [1,2,3,4] >>> squared_list = map(lambda x: x**2, a)
如果你掌握lambdas和映射,你将有一个巨大的力量来操纵数据,并以一个简洁的方式。 Lambda函数既不晦涩,也不会消除代码的清晰度。 不要把一些困难的东西与新的东西混淆。 一旦你开始使用它们,你会发现它非常清楚。
我不能说python的lambda的特定实现,但一般lambda函数真的很方便。 它们是函数式编程的核心技术(甚至可能是技术),在面向对象的程序中也是非常有用的。 对于某些types的问题,他们是最好的解决scheme,所以当然不应该被遗忘!
我build议你阅读closures和映射函数 (链接到python文档,但它几乎存在于每种支持函数结构的语言),看看为什么它是有用的。
在我看来, lambda
之一是低估了简单forms的评估,直到需要价值。 让我解释。
许多库例程都被实现,以便它们允许某些参数是可调用的(其中lambda是一个参数)。 这个想法是,实际的价值将被计算,只有在它将被使用的时候(而不是被调用的时候)。 一个(做作的)例子可能有助于说明这一点。 假设你有一个例程,它会logging一个给定的时间戳。 你希望例程使用当前时间减去30分钟。 你会这样称呼它
log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))
现在假设只有当某个事件发生时才会调用实际函数,并且只希望在此时计算时间戳。 你可以这样做
log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))
假设log_timestamp
可以像这样处理可调用的对象,它会在需要的时候对它进行评估,这样你就可以得到时间戳了。
当然有其他方法可以做到这一点(例如使用operator
模块),但是我希望我已经传达了这一点。
更新 : 这是一个稍微更具体的现实世界的例子。
更新2 :我认为这是所谓的thunk的一个例子。
如上所述,Python中的lambda运算符定义了一个匿名函数,在Python函数中是闭包。 重要的是不要把封闭的概念和操作符lambda混为一谈,这只是对他们的句法美沙酮。
当我几年前开始使用Python时,我使用了很多lambdas,认为它们很酷,还有列表parsing。 但是,我写了并且必须维护一个用Python编写的大网站,大约有几千个function点。 我从经验中学习到lambda可能可以用来创build原型,但除了保存几个关键字或者有时候不提供内联函数(命名闭包)之外没有其他的东西。
基本上这可以归结为几点:
- 阅读使用有意义的名字明确书写的软件更容易。 根据定义匿名closures不能有一个有意义的名字,因为他们没有名字。 由于某种原因,这个简洁似乎也会感染lambda参数,因此我们经常会看到像lambda x:x + 1
- 当命名闭包被重用时更容易,因为当名称被引用时,它们可以被多次引用。
- debugging使用命名闭包而不是使用lambdaexpression式的代码更容易,因为名称将出现在回溯中以及错误周围。
这是足够的理由,把他们转换成命名闭包。 不过,我还有两个对匿名closures的怨恨。
第一个嫉妒只不过是他们只是另一个不必要的关键词而已。
第二个嫉妒更深层次,也就是范式层面,即我不喜欢他们提倡的function性编程风格,因为这种风格比消息传递,面向对象或程序风格更不灵活,因为lambda演算不是图灵 – 完成(幸运的是,在Python中,我们仍然可以在lambda内部突破这个限制)。 我觉得推广这种风格的原因是:
-
有一个隐含的回报,即他们似乎应该是function。
-
它们是另一种更明确,更可读,更可重用和更一般的机制:方法的替代性国家隐藏机制。
我努力编写无lambda的Python,并去除lambdas。 我认为Python没有lambdaexpression式会是一个稍微好一些的语言,但这只是我的意见。
Lambdas实际上是非常强大的构造,它源自于函数式编程中的想法,在Python不久的将来,它决不会被轻易地修改,重新定义或移除。 他们帮助你编写更强大的代码,因为它允许你传递函数作为参数,从而成为一等公民的function。
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在他的回答中所提到的,列表推导并不总是顺其自然的方式,特别是如果你的列表必须从一些模糊的math方法中获得价值。
从更实际的angular度来看,最近我对lambda的最大优点之一就是GUI和事件驱动的编程。 如果你看看Tkinter的callback,他们所有的参数都是触发它们的事件。 例如
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
现在你可以争辩说,这可以用全局variables来完成,但是你是否真的想要让你担心内存pipe理和泄漏,特别是如果全局variables只能用在一个特定的地方呢? 那将只是糟糕的编程风格。
总之,lambda是令人敬畏的,不应该被低估。 虽然Python的lambdaexpression式和LISP的lambdaexpression式并不相同,但是你可以用它们做很多不可思议的事情。
一般来说,Lambda都非常喜欢函数式编程风格。 通过对数据应用函数并合并结果可以解决问题的想法是Google用来实现其大部分algorithm的原因。 以function编程风格编写的程序很容易并行化,因此在现代多核机器中变得越来越重要。 所以总之,不,你不应该忘记他们。
首先恭喜,设法找出lambda。 在我看来,这是非常强大的行为。 现在趋向于函数式编程语言的趋势肯定是一个既不应该避免也不会在不久的将来被重新定义的指标。
你只需要考虑一点点不同。 我相信很快你会爱上它。 但是要小心,如果你只处理python。 因为lambda不是一个真正的封闭,所以它会被破坏: pythons lambda被破坏
我刚刚开始Python,首先跑到Lambda–这花了我一段时间才弄清楚。
请注意,这不是对任何事物的谴责。 每个人都有不同的一套不容易的事情。
拉姆达是那些在现实生活中应该被遗忘的“有趣的”语言项目之一吗?
没有。
我敢肯定,在某些情况下可能需要边缘情况下,但由于它的模糊,
这不是模糊的。 过去两队我一直在使用这个function。
在将来的版本中重新定义了它的潜力(我根据它的各种定义进行了假设)
除了几年前修复闭包语义之外,我没有看到任何认真的build议来重新定义Python。
编码清晰度降低 – 是否应该避免?
如果你正确地使用它,这并不是不太清楚。 相反,有更多的语言结构可以增加清晰度。
这让我想起了Ctypes的溢出(缓冲区溢出) – 指向顶部variables和重载设置其他字段值…sorting技术娴熟,但维修编码器噩梦..
Lambda就像缓冲区溢出? 哇。 我无法想象你如何使用lambda,如果你认为这是一个“维护噩梦”。
我今天开始阅读David Mertz的书“Python中的文本处理”。 虽然他对Lambda的第一章中的例子进行了相当简单的描述,但是结合附录A中的解释让他们跳下了我(最后),突然之间我明白了他们的价值。 这并不是说他的解释对你有用,而且我仍然处于发现阶段,所以除了以下内容,我不会试图添加这些答案:我是Python的新手我是OOP的新手Lambdas是一个为我而奋斗的人现在我读了Mertz,我想我可以得到他们,我认为他们是非常有用的,因为我认为他们允许更清晰的编程方法。
He reproduces the Zen of Python, one line of which is Simple is better than complex. As a non-OOP programmer reading code with lambdas (and until last week list comprehensions) I have thought- This is simple? 。 I finally realized today that actually these features make the code much more readable, and understandable than the alternative-which is invariably a loop of some sort. I also realized that like financial statements-Python was not designed for the novice user, rather it is designed for the user that wants to get educated. I can't believe how powerful this language is. When it dawned on me (finally) the purpose and value of lambdas I wanted to rip up about 30 programs and start over putting in lambdas where appropriate.
I can give you an example where I actually needed lambda serious. I'm making a graphical program, where the use right clicks on a file and assigns it one of three options. It turns out that in Tkinter (the GUI interfacing program I'm writing this in), when someone presses a button, it can't be assigned to a command that takes in arguments. So if I chose one of the options and wanted the result of my choice to be:
print 'hi there'
Then no big deal. But what if I need my choice to have a particular detail. For example, if I choose choice A, it calls a function that takes in some argument that is dependent on the choice A, B or C, TKinter could not support this. Lamda was the only option to get around this actually…
I use lambdas to avoid code duplication. It would make the function easily comprehensible Eg:
def a_func() ... if some_conditon: ... call_some_big_func(arg1, arg2, arg3, arg4...) else ... call_some_big_func(arg1, arg2, arg3, arg4...)
I replace that with a temp 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)
I'm a python beginner, so to getter a clear idea of lambda I compared it with a 'for' loop; in terms of efficiency. Here's the code (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)
I use it quite often, mainly as a null object or to partially bind parameters to a function.
这里是例子:
to implement null object pattern:
{ DATA_PACKET: self.handle_data_packets NET_PACKET: self.handle_hardware_packets }.get(packet_type, lambda x : None)(payload)
for parameter binding:
let say that I have the following API
def dump_hex(file, var) # some code pass class X(object): #... def packet_received(data): # some kind of preprocessing self.callback(data) #...
Then, when I wan't to quickly dump the recieved data to a file I do that:
dump_file = file('hex_dump.txt','w') X.callback = lambda (x): dump_hex(dump_file, x) ... dump_file.close()
A useful case for using lambdas is to improve the readability of long list comprehensions . In this example loop_dic
is short for clarity but imagine loop_dic
being very long. If you would just use a plain value that includes i
instead of the lambda version of that value you would get a 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'}]
I use lambda
to create callbacks that include parameters. It's cleaner writing a lambda in one line than to write a method to perform the same functionality.
例如:
import imported.module def func(): return lambda: imported.module.method("foo", "bar")
as opposed to:
import imported.module def func(): def cb(): return imported.module.method("foo", "bar") return cb
Lambda is a procedure constructor. You can synthesize programs at run-time, although Python's lambda is not very powerful. Note that few people understand that kind of programming.