提问人:meade 提问时间:5/21/2009 最后编辑:martineaumeade 更新时间:12/19/2021 访问量:586799
lambda 有什么用?[已结束]
How are lambdas useful? [closed]
问:
我正在尝试弄清楚 Python lambda。在现实生活中,那些“有趣”的语言项目之一应该被遗忘吗?lambda
我敢肯定,在一些边缘情况下可能需要它,但考虑到它的模糊性,它在未来版本中被重新定义的可能性(我基于它的各种定义的假设)以及降低的编码清晰度 - 应该避免吗?
这让我想起了 C 类型的溢出(缓冲区溢出)——指向顶部变量并重载以设置其他字段值。这感觉像是一种技术表演,但维护编码员的噩梦。
答:
我不能说 python 的 lambda 特定实现,但总的来说 lambda 函数真的很方便。它们是函数式编程的核心技术(甚至可能是 THE 技术),它们在面向对象的程序中也非常有用。对于某些类型的问题,它们是最好的解决方案,所以当然不应该忘记!
我建议你阅读闭包和 map 函数(链接到 python 文档,但它几乎存在于所有支持函数式构造的语言中),以了解它为什么有用。
评论
几乎所有你可以用你做的事,你都可以用命名函数或列表和生成器表达式做得更好。lambda
因此,在大多数情况下,您基本上在任何情况下都应该只使用其中之一(除了在交互式解释器中编写的临时代码)。
评论
我怀疑 lambda 会消失。 请参阅 Guido 关于最终放弃尝试删除它的帖子。另请参阅冲突的概述。
你可以看看这篇文章,了解更多关于 Python 功能特性背后的交易历史: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html
奇怪的是,最初促使引入 lambda 和其他功能特性的 map、filter 和 reduce 函数在很大程度上已被列表推导式和生成器表达式所取代。事实上,在 Python 3.0 中,reduce 函数已从内置函数列表中删除。(但是,没有必要发送有关删除 lambda、map 或过滤器的投诉:它们会留下来。
我自己的两分钱:就清晰度而言,很少有 lambda 值得。通常,有一个更明确的解决方案不包括 lambda。
评论
Lambda 通常与函数式编程风格密切相关。您可以通过将函数应用于某些数据并合并结果来解决问题的想法是谷歌用来实现其大部分算法的想法。
以函数式编程风格编写的程序很容易并行化,因此在现代多核机器中变得越来越重要。 所以简而言之,不,你不应该忘记他们。
首先恭喜你设法弄清楚了lambda。在我看来,这是一个非常强大的结构。如今,函数式编程语言的趋势无疑是一个指标,表明它既不应该被避免,也不会在不久的将来被重新定义。
你只需要想一点不同。我相信很快你会喜欢它。但是,如果您只处理python,请小心。因为 lambda 不是一个真正的闭包,所以它以某种方式被“破坏”了:pythons lambda 被破坏了
评论
我已经使用 Python 几年了,我从来没有遇到过需要 lambda 的情况。真的,正如教程所述,它只是为了语法糖。
评论
lambda 是一个非常重要的抽象机制的一部分,它处理高阶函数。为了正确理解它的价值,请观看 Abelson 和 Sussman 的高质量课程,并阅读 SICP 一书
这些都是现代软件业务中的相关问题,并且变得越来越流行。
评论
lambda
lambda
你说的是 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])
设置为 ,原始列表中的那些元素是 3 的倍数。这比mult3
[3, 6, 9]
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]
(甚至作为 ),但还有许多其他更复杂的使用案例,您不能使用列表推导式,而 lambda 函数可能是写出某些内容的最短方法。range(3,10,3)
从另一个函数返回一个函数
>>> 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 是一个过程构造函数。您可以在运行时合成程序,尽管 Python 的 lambda 不是很强大。请注意,很少有人理解这种编程。
我刚刚开始使用 Python,并首先进入了 Lambda——这花了我一段时间才弄清楚。
请注意,这不是对任何事情的谴责。每个人都有不同的事情,这些事情来之不易。
lambda 是现实生活中应该被遗忘的“有趣”语言项目之一吗?
不。
我敢肯定,在一些边缘情况下可能需要它,但考虑到它的晦涩难懂,
它并不晦涩难懂。在我工作过的过去 2 个团队中,每个人都一直在使用这个功能。
它在未来版本中被重新定义的潜力(我基于它的各种定义的假设)
除了几年前修复闭包语义之外,我还没有看到在 Python 中重新定义它的严肃建议。
以及降低的编码清晰度 - 应该避免吗?
如果你用得对,这也不是不太清楚。相反,拥有更多的语言结构可以提高清晰度。
这让我想起了 C 类型的溢出(缓冲区溢出)——指向顶部变量并重载以设置其他字段值......有点像技术表演,但维护编码员的噩梦......
Lambda 就像缓冲区溢出?哇。如果您认为 lambda 是“维护噩梦”,我无法想象您如何使用 lambda。
评论
我经常使用它,主要是作为 null 对象或将参数部分绑定到函数。
以下是示例:
要实现 null 对象模式,请执行以下操作:
{
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
评论
a = int(input("Enter a number:\n> ")); add=(lambda x: a+x); b = int(input("Enter another number:\n> ")); print("The sum of these numbers is", add(b))
f
a
a
a
import f from this_comment
我今天开始阅读 David Mertz 的书《Python 中的文本处理》。虽然他对 Lambda 的描述相当简洁,但第一章中的例子与附录 A 中的解释相结合,使它们(最终)为我跳出了页面,突然间我明白了它们的价值。这并不是说他的解释对你有用,我仍处于发现阶段,所以我不会尝试添加这些回复,除了以下内容: 我是 Python 新手 我是 OOP 的新手 Lambda 对我来说是一场斗争 现在我读了 Mertz,我想我明白了,我认为它们非常有用,因为我认为它们允许更简洁的编程方法。
他再现了 Python 的禅宗,其中一行是“简单胜于复杂”。作为一个非 OOP 程序员,使用 lambda 阅读代码(直到上周列表理解),我一直认为——这很简单?我今天终于意识到,实际上这些特性使代码比替代方案更具可读性和可理解性——后者总是某种循环。我还意识到,就像财务报表一样,Python 不是为新手用户设计的,而是为想要接受教育的用户设计的。我简直不敢相信这种语言有多强大。当我(终于)意识到 lambda 的目的和价值时,我想撕毁大约 30 个程序,并在适当的地方重新开始放入 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'>
老实说,我认为这个关键字在 Python 中是多余的——我从来没有需要使用它们(或者看到过一个使用常规函数、列表推导或许多内置函数之一可以更好地使用)lambda
举一个完全随机的例子,来自文章“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())
这样做会使用额外的参数调用该方法并导致错误。使用 lambda 意味着我们可以整齐地删除参数,而无需定义包装函数。w.textChanged.connect(dothing)
dothing
event
评论
a
__name__
lambda
只是一种花哨的说法.除了它的名字之外,它没有什么晦涩、令人生畏或神秘的东西。当您阅读以下行时,请在脑海中替换为:function
lambda
function
>>> f = lambda x: x + 1
>>> f(3)
4
它只是定义了 的函数。其他一些语言,比如 ,明确地说出来:x
R
> f = function(x) { x + 1 }
> f(3)
4
你看?这是编程中最自然的事情之一。
评论
return
lambda
function
type(lambda x: 3)
lambda
def
function
lambda
lambda
lambda
f = lambda x: x + 1
def f(x): return(x+1)
在我看来,它被低估了,其中一件好事是,它是将对简单表单的评估推迟到需要值之前的方式。让我解释一下。lambda
许多库例程的实现使它们允许某些参数是可调用的(lambda 就是其中之一)。这个想法是,实际值将仅在使用它时(而不是在调用它时)计算。一个(人为的)例子可能有助于说明这一点。假设你有一个例程,它将记录一个给定的时间戳。您希望例程使用当前时间减去 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 的一个例子。
我发现 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'
如果你必须为所有这些定义一个函数,你会在它结束时发疯。
此外,使用 、 等函数名称也不好。当你依赖于一个变量函数 id 时,你就需要它。plural_rule_1
plural_rule_2
eval()
评论
如上所述,Python 中的 lambda 运算符定义了一个匿名函数,而在 Python 中,函数是闭包。重要的是不要将闭包的概念与运算符 lambda 混淆,后者对它们来说只是句法美沙酮。
几年前,当我开始使用 Python 时,我经常使用 lambda,认为它们很酷,还有列表推导。但是,我编写并且必须维护一个用 Python 编写的大型网站,大约有几千个功能点。我从经验中了解到,lambda 可能可以用于原型设计,但除了保存一些键控之外,除了保存一些键控或有时不提供任何内联函数(称为闭包)之外,什么都不提供。
基本上,这归结为几点:
- 使用有意义的名称显式编写的软件更容易阅读。根据定义,匿名闭包不能具有有意义的名称,因为它们没有名称。出于某种原因,这种简洁性似乎也感染了 lambda 参数,因此我们经常看到像 lambda x: x+1 这样的例子
- 重用命名闭包更容易,因为当有名称可以引用它们时,它们可以多次被引用。
- 调试使用命名闭包而不是 Lambda 的代码更容易,因为该名称将出现在回溯中,并出现在错误周围。
这足以将它们四舍五入并将它们转换为命名闭包。但是,我对匿名关闭还有另外两个怨恨。
第一个怨恨只是它们只是另一个不必要的关键字,使语言变得混乱。
第二个怨恨更深,在范式层面上,即我不喜欢他们提倡函数式编程风格,因为这种风格不如消息传递、面向对象或过程风格灵活,因为 lambda 演算不是图灵完备的(幸运的是,在 Python 中,即使在 lambda 中,我们仍然可以打破这个限制)。我觉得 lambdas 推广这种风格的原因是:
有一个隐式返回,即它们看起来“应该”是函数。
它们是另一种更明确、更易读、更可重用和更通用的机制的替代状态隐藏机制:方法。
我努力编写无 lambda 的 Python,并在看到时删除 lambda。我认为没有 lambda 的 Python 会是一种稍微好一点的语言,但这只是我的看法。
评论
Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
lambda 在 GUI 编程中非常有用。例如,假设您正在创建一组按钮,并且希望使用单个参数化回调,而不是每个按钮的唯一回调。借助 Lambda,您可以轻松实现此目的:
for value in ["one","two","three"]:
b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
b.pack()
(注意:虽然这个问题是专门问的,但你也可以使用functools.partial来得到相同类型的结果)lambda
另一种方法是为每个按钮创建一个单独的回调,这可能会导致重复的代码。
评论
value
arg=value
functools.partial
partial(my_callback, value)
vs - lambda 有更多的 cruft(分配给 arg 然后使用),并且不太清楚意图是什么(您可能在 lambda 中做一些微妙的不同的事情)。导入并不是真正的问题(反正你有一堆,每个文件一次)。代码的最佳判断标准是它的阅读能力,并且比 lambda 更容易阅读。lambda arg=value: my_callback(arg)
partial()
我可以举个例子,我实际上需要认真对待 lambda。我正在制作一个图形程序,其中使用右键单击文件并为其分配三个选项之一。事实证明,在 Tkinter(我正在编写此内容的 GUI 接口程序)中,当有人按下按钮时,它不能分配给接受参数的命令。因此,如果我选择了其中一个选项并希望我选择的结果是:
print 'hi there'
那就没什么大不了的。但是,如果我需要我的选择有一个特定的细节怎么办。例如,如果我选择选项 A,它会调用一个函数,该函数接受依赖于选项 A、B 或 C 的某个参数,TKinter 无法支持这一点。实际上,Lamda是解决这个问题的唯一选择......
评论
def foo...
foo
lambda
使用 lambda 的一个有用案例是提高长列表推导的可读性。
在这个例子中,为了清楚起见,它是简短的,但想象一下很长。如果您只使用包含该值的普通值而不是 lambda 版本,则将获得 .loop_dic
loop_dic
i
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 实际上是非常强大的结构,它源于函数式编程的思想,在不久的将来,它绝不会轻易被修改、重新定义或删除。它们可以帮助您编写更强大的代码,因为它允许您将函数作为参数传递,从而将函数视为一等公民。
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
widget.bind
event
event
do-something-cool
x
y
do-something-cool
do-something-cool
我使用 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)
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]
现在让我们使用地图,这是一回事,但更中立。Maps 有 2 个参数:
(i) 一个功能
(ii) 可迭代对象
并为您提供一个列表,其中每个元素都是应用于可迭代对象的每个元素的函数。
因此,使用地图,我们将有:
>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)
如果您掌握了 lambda 和映射,您将拥有强大的能力以简洁的方式操作数据。Lambda 函数既不晦涩难懂,也不影响代码的清晰度。不要将困难的东西与新的东西混为一谈。一旦你开始使用它们,你会发现它非常清楚。
我用于创建包含参数的回调。在一行中编写 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
我是 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)
评论