我正在尝试找出Python lambda。lambda是在现实生活中应该被遗忘的那些“有趣”语言项目之一吗?
我确定在某些情况下可能需要使用它,但是鉴于它的晦涩之处,在将来的版本中重新定义了它的潜力(根据各种定义我的假设)以及降低的编码清晰度-是否应该被避免?
这让我想起了C类型的溢出(缓冲区溢出)-指向顶部变量,并通过重载来设置其他字段值。感觉像是技术娴熟的演艺风格,但却是维护编码员的噩梦。
我正在尝试找出Python lambda。lambda是在现实生活中应该被遗忘的那些“有趣”语言项目之一吗?
我确定在某些情况下可能需要使用它,但是鉴于它的晦涩之处,在将来的版本中重新定义了它的潜力(根据各种定义我的假设)以及降低的编码清晰度-是否应该被避免?
这让我想起了C类型的溢出(缓冲区溢出)-指向顶部变量,并通过重载来设置其他字段值。感觉像是技术娴熟的演艺风格,但却是维护编码员的噩梦。
Answers:
您是在谈论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]
,原始列表的那些元素是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函数。我花了一些时间来适应它们,但最终我了解到它们是语言中非常有价值的一部分。
','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
lambda
函数可以是匿名的(就像您所有示例中一样)。如果您要lambda
为任何东西分配一个函数,那么您就做错了,应该def
改用
lambda
只是一种幻想的表达方式function
。除了它的名字,没有什么晦涩,令人生畏或神秘的东西。阅读以下行时,请以替换lambda
为function
:
>>> f = lambda x: x + 1
>>> f(3)
4
它只是定义的功能x
。其他一些语言(如R
)则明确指出:
> f = function(x) { x + 1 }
> f(3)
4
你看?这是编程中最自然的事情之一。
lambda
非常易于理解。谢谢!
lambda
为function
,并return
在最后一个表达之前添加
type(lambda x: 3)
。lambda
表达式和def
语句都生成function
对象;只是lambda
表达式的语法限制了它可以产生哪些实例。
lambda
表达式并不意味着结果lambda
表达不是一个功能。
Lambda是非常重要的抽象机制的一部分,该机制处理高阶函数。为了正确理解其价值,请观看Abelson和Sussman的高质量课程,并阅读SICP书
这些是现代软件业务中的相关问题,并且变得越来越流行。
lambda
s和一流的功能。Python的lambda
语句非常有限,但是功能完全一流。唯一的区别是您必须命名要传递的功能。
lambda在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获得相同类型的结果)
另一种方法是为每个按钮创建一个单独的回调,这可能导致代码重复。
value
是在循环中定义的;在另一个示例中,参数始终只有一个值。当您添加类似的内容时arg=value
,您会将当前值附加到回调中。没有它,您就将引用绑定到回调中的变量。该引用将始终包含变量的最终值,因为回调发生在循环已完成运行后的某个时间。
functools.partial()
它的存在使您可以减少工作量(并且没有lambda
)。
partial(my_callback, value)
vs lambda arg=value: my_callback(arg)
-Lambda有更多的不足之处(分配给arg,然后分配用法),并且目的是不清楚(您可能会在lambda中做一些细微的变化)。导入并不是真正的问题(无论如何,您都有很多,每个文件一次)。最好根据代码的读取程度来判断代码,并且partial()
比lambda易于阅读。
我怀疑lambda会消失。有关最终放弃尝试删除它的信息,请参见Guido的文章。另请参阅冲突概述。
您可以查看此帖子,以获得有关Python功能特性背后交易的更多历史记录:http : //python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html
奇怪的是,最初促使引入lambda和其他功能特征的map,filter和reduce功能在很大程度上已被列表理解和生成器表达式所取代。实际上,reduce函数已从Python 3.0中的内置函数列表中删除。(但是,没有必要发送有关删除lambda,地图或过滤器的投诉:它们正在留下。:-)
我自己的2美分:就清晰程度而言,lambda很少值得。通常,有一个更清晰的解决方案,其中不包含lambda。
在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
。第一次尝试:>>> fs = [(lambda n: i + n) for i in range(10)] >>> fs[3](4) 13
我会争辩说,即使这样做确实可行,这也是可怕的和“非pythonic的”,可以用无数其他方式编写相同的功能,例如:
>>> 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意味着我们可以整齐地删除参数,而不必定义包装函数。
a
您定义的lambda和function 并不完全相同。:)他们__name__
至少因领域而异...
我发现lambda对于执行相同功能但对于不同情况的功能列表很有用。
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
等)也不是很好。而且eval()
,当您依赖于可变函数id时就需要使用它。
lambda
使用命名函数或列表和生成器表达式,几乎可以做的任何事情都可以做得更好。
因此,在大多数情况下,您基本上只应该是在任何情况下都可以选择的一种(可能不是交互式解释器中编写的草稿代码)。
我已经使用Python几年了,但从未遇到过需要 lambda的情况。确实,如本教程所述,它仅用于语法糖。
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:“放入a中的每个元素”
方便吗?创建这样的功能。让我们使用lambda重写它:
>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]
现在让我们使用地图,这是一回事,但是在语言上是中立的。地图采用2个参数:
(i)一个功能
(ii)可迭代
并为您提供一个列表,其中每个元素都是应用于可迭代元素的函数。
因此,使用map我们将拥有:
>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)
如果您掌握lambda和映射,那么您将拥有以简洁的方式操作数据的强大能力。Lambda函数既不模糊也不使代码清晰。不要将困难与新事物混淆。一旦开始使用它们,您会发现它非常清晰。
lambda
在我看来,其中的一件好事被低估了,它是将简单形式的评估推迟到需要该值之前的一种方式。让我解释。
实现了许多库例程,以便它们允许某些参数是可调用的(lambda是其中的一个)。想法是,仅在将要使用实际值时(而不是在调用它时)才计算实际值。一个(人为的)示例可能有助于说明这一点。假设您有一个要记录给定时间戳记的例程。您希望例程使用当前时间减去30分钟。你会这样称呼它
log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))
现在,假设仅当某个事件发生并且您希望仅在该时间计算时间戳时才调用实际函数。你可以这样做
log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))
假设log_timestamp
can可以处理这样的可调用对象,它将在需要时对其进行评估,届时您将获得时间戳。
当然,还有其他方法可以做到这一点(operator
例如,使用模块),但我希望我已经传达了这一点。
更新:这是一个更具体的现实示例。
更新2:我认为这是所谓的“ thunk”的示例。
如上所述,Python中的lambda运算符定义了一个匿名函数,而在Python函数中则是闭包。重要的是不要将闭包的概念与运算符lambda混淆,后者只是语法上的美沙酮。
几年前,当我开始使用Python时,我经常使用lambda,认为它们很酷,而且很理解列表。但是,我编写并必须维护一个用Python编写的大型网站,其功能点约为数千个。我从经验中学到,lambda可以用它们进行原型制作,但是除了保存一些键调用(有时甚至不保存)之外,内联函数(命名为闭包)什么也没有提供。
基本上可以归结为以下几点:
这足以将它们四舍五入并将其转换为命名的闭包。但是,我对匿名关闭持另外两个怨恨。
第一个怨恨就是它们只是使语言混乱的另一个不必要的关键字。
第二个怨恨在范式层次上更深,也就是说,我不喜欢它们提倡一种函数式编程风格,因为这种风格比消息传递,面向对象或过程风格的灵活性差,因为lambda演算不是Turing- complete(幸运的是,在Python中,即使在lambda中,我们仍然可以突破该限制)。我觉得Lambda推广这种风格的原因是:
有一个隐式的回报,即它们似乎“应该”是函数。
它们是另一种更清晰,更易读,更可重用且更通用的机制:方法的状态隐藏机制。
我努力编写无lambda的Python,并删除可见的lambda。我认为如果没有lambda,Python会是一种更好的语言,但这只是我的观点。
Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Lambda实际上是非常强大的构造,其源于函数式编程的思想,并且在不久的将来Python绝不会轻易对其进行修改,重新定义或删除。它们可以帮助您编写功能更强大的代码,因为它允许您将函数作为参数进行传递,从而使函数成为一流公民。
Lambda的确容易引起混淆,但是一旦获得了扎实的理解,您就可以编写干净的优雅代码,如下所示:
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在他的回答中提到的那样,列表理解并非总是可行的,特别是如果您的列表必须从某种晦涩的数学方法中获取值。
从更实际的角度来看,lambda的最大优点之一对我来说是GUI和事件驱动的编程。如果您看一下Tkinter中的回调,则将它们当作参数的是触发它们的事件。例如
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
现在您可以争辩说可以使用全局变量来完成此操作,但是您是否真的想担心内存管理和泄漏,特别是如果全局变量仅在一个特定的地方使用时呢?那将是糟糕的编程风格。
简而言之,lambda非常棒,绝对不能低估它。尽管Python Lambda与LISP Lambda(功能更强大)不同,但是您确实可以用它们做很多神奇的事情。
main
和中do_something_cool
如何定义?发生什么x
,并y
在功能?传递的值似乎会立即被覆盖?函数如何得知event
?您可以添加一些评论/解释吗?谢谢
x
,并y
作为参数do-something-cool
和它们的值的功能设定,说明了如何使用lambda表达式来传递,其中没有一个是预期的参数。该widget.bind
函数需要一个event
参数来标识该特定小部件上的GUI事件。我建议阅读Tkinter的编程模型以更清晰。
x,y
然后做x=event.x
。那不会覆盖您传递的值吗?函数如何知道是什么event
?我看不到将其传递给函数的位置。还是一种方法?您还可以在函数名称中使用减号吗?
x, y
,这只是出于说明目的的示例。我试图展示lambda的力量,而不是Tkinter。:)
event
?在这种情况下,您的lambda不应该阅读lambda event: do_something_cool(event,x,y)
吗?
首先恭喜您找出了lambda。在我看来,这是一个非常强大的构造。如今,趋向于函数式编程语言的趋势无疑表明,既不应该避免也不希望在不久的将来重新定义它。
您只需要稍微有所不同即可。我相信您很快就会喜欢它。但是,如果仅处理python,请小心。因为lambda不是真正的闭包,所以它以某种方式“被破坏了”:pythons lambda被破坏了
我才刚开始使用Python,然后先进入Lambda,这花了我一段时间才弄清楚。
请注意,这并不是对任何事情的谴责。每个人都有一套不同的事情,这些事情并非易事。
lambda是在现实生活中应该被遗忘的那些“有趣”语言项目之一吗?
没有。
我确定在某些情况下可能需要使用它,但是鉴于它的晦涩之处,
这不是晦涩的。我工作的过去2个团队中,每个人都一直使用此功能。
在将来的版本中重新定义它的潜力(我基于它的各种定义的假设)
除了几年前修复闭包语义外,我还没有认真的提议在Python中重新定义它。
以及降低的编码清晰度-应该避免吗?
如果使用得当,还不清楚。相反,拥有更多可用的语言构造可提高清晰度。
这让我想起了C类型的溢出(缓冲区溢出)-指向顶部变量,并重载了设置其他字段的值。
Lambda就像缓冲区溢出吗?哇。如果您认为这是“维护噩梦”,我无法想象您将如何使用lambda。
我使用lambda来避免代码重复。它将使函数易于理解,例如:
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)
我今天开始阅读David Mertz的书“ Python中的文本处理”。尽管他对Lambda的描述非常简洁,但结合了附录A中的解释使第一章的示例对我来说(最终)从页面上跳了下来,突然之间我明白了它们的价值。并不是说他的解释对您有用,我仍然处于发现阶段,因此除了以下内容之外,我不会尝试添加其他答复:我是Python新手,还是OOP Lambdas新手。既然我读了Mertz,我想我会得到它们,并且我认为它们非常有用,因为我认为它们允许使用更简洁的编程方法。
他再现了Python的Zen,其中的一句话是简单胜于复杂。作为一个非OOP程序员,使用lambda读取代码(直到上周列出了理解),我曾想过- 这很简单吗?。我今天终于意识到,实际上这些功能使代码比替代方案更具可读性和可理解性,而替代方案始终是某种形式的循环。我还意识到,就像财务报表一样,Python并不是为新手用户设计的,而是为希望受过教育的用户设计的。我不敢相信这种语言有多么强大。当我终于意识到了lambda的目的和价值时,我想撕碎大约30个程序,并在适当的地方重新开始使用lambda。
使用lambda的一个有用案例是提高长列表理解的可读性。在此示例中,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'}]
我可以举一个例子,说明我实际上需要严重的lambda。我正在制作一个图形程序,其中使用权在文件上单击并为其分配三个选项之一。事实证明,在Tkinter(我正在编写的GUI接口程序)中,当有人按下按钮时,无法将其分配给带有参数的命令。因此,如果我选择其中一个选项并希望选择的结果是:
print 'hi there'
那没什么大不了的。但是,如果我需要选择一个特定的细节怎么办?例如,如果我选择选项A,则它调用一个函数,该函数接受依赖于选项A,B或C的某些参数,TKinter不支持此功能。实际上,Lamda是解决此问题的唯一选择。
def foo...
,然后再通过foo
而不是lambda
。这只是更多的代码,您必须提供一个名称。
我经常使用它,主要是作为空对象或将参数部分绑定到函数。
以下是示例:
{
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()
我是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)
Lambda是一个过程构造函数。尽管Python的lambda并不是很强大,但是您可以在运行时合成程序。请注意,很少有人了解这种编程。