Lambda表达式是有用的Python函数:为什么?

Why are Python lambdas useful?

我想弄明白Python羊羔。lambda是否是那些在现实生活中应该被遗忘的"有趣的"语言项目之一?

我确信在某些边缘情况下可能需要它,但是考虑到它的模糊性,它在未来版本中被重新定义的可能性(我的假设基于它的各种定义)和降低的编码清晰度——应该避免它吗?

这使我想起C类型的溢出(缓冲区溢出)-指向顶部变量并重载以设置其他字段值。这感觉像是一种技术表演,但维护编码的噩梦。


你在说lambda函数吗?喜欢

1
lambda x: x**2 + 2*x - 5

这些东西实际上很有用。python支持一种称为函数式编程的编程风格,在这种编程风格中,您可以将函数传递给其他函数来完成工作。例子:

1
mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

mult3设置为[3, 6, 9],原始列表中的那些元素是3的倍数。这比

1
2
3
def filterfunc(x):
    return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

当然,在这种特殊情况下,您可以做与列表理解相同的事情:

1
mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(或者甚至和range(3,10,3)一样),但是还有许多其他更复杂的用例,您不能使用列表理解,lambda函数可能是写出某些东西的最短方法。

  • 从另一个函数返回函数

    1
    2
    3
    4
    5
    6
    >>> def transform(n):
    ...     return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    这通常用于创建函数包装器,如Python的装饰器。

  • 把一个可重复序列的元素与reduce()结合起来

    1
    2
    >>> 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'
  • 按备用键排序

    1
    2
    >>> 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替换lambda

1
2
3
>>> f = lambda x: x + 1
>>> f(3)
4

它只是定义了x的一个函数。其他一些语言,如R明确表示:

1
2
3
> f = function(x) { x + 1 }
> f(3)
4

你明白了吗?这是编程中最自然的事情之一。


两行摘要:

  • 闭包:非常有用。学习他们,使用他们,爱他们。
  • python的lambda关键字:不必要,偶尔有用。如果你发现你自己在做任何远程复杂的事情,把它收起来,定义一个真正的函数。

  • lambda是处理高阶函数的非常重要的抽象机制的一部分。为了正确理解它的价值,请观看Abelson和Sussman的优质课程,并阅读SICP一书。

    这些都是现代软件业务中的相关问题,并且越来越流行。


    我怀疑lambda会消失。看看吉多的文章,关于最终放弃尝试移除它。另见冲突概要。

    您可以查看本文了解更多关于Python功能特性背后交易的历史记录:http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

    Curiously, the map, filter, and reduce functions that originally motivated the introduction of lambda and other functional features have to a large extent been superseded by list comprehensions and generator expressions. In fact, the reduce function was removed from list of builtin functions in Python 3.0. (However, it's not necessary to send in complaints about the removal of lambda, map or filter: they are staying. :-)

    我自己的两分钱:就清晰度而言,lambda几乎不值得。一般来说,有一个更清晰的解决方案不包括lambda。


    lambda在GUI编程中非常有用。例如,假设您正在创建一组按钮,并且希望使用单个参数化回调而不是每个按钮的唯一回调。lambda让您轻松完成:

    1
    2
    3
    for value in ["one","two","three"]:
        b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
        b.pack()

    (注:虽然这个问题是专门问lambda的问题,但也可以使用functools.partial得到相同类型的结果)

    另一种方法是为每个按钮创建一个单独的回调,这可能导致重复的代码。


    在python中,lambda只是一种内联定义函数的方法,

    1
    2
    a = lambda x: x + 1
    print a(1)

    并且…

    1
    2
    def a(x): return x + 1
    print a(1)

    …完全一样。

    对于lambda,您不能做任何不能用常规函数做的事情—在python函数中,与其他任何函数一样,lambda只是定义一个函数:

    1
    2
    3
    >>> a = lambda x: x + 1
    >>> type(a)
    <type 'function'>

    老实说,我认为在python中,lambda关键字是多余的;我从来没有必要使用它们(或者看到一个用于常规函数、列表理解或许多内置函数中的一个可以更好地使用的函数)。

    对于一个完全随机的例子,从文章"python's lambda is broken!":

    To see how lambda is broken, try generating a list of functions fs=[f0,...,f9] where fi(n)=i+n. First attempt:

    1
    2
    3
    >>> fs = [(lambda n: i + n) for i in range(10)]
    >>> fs[3](4)
    13

    我会争辩说,即使这确实有效,但它是可怕的和"不完美的",同样的功能可以用无数其他方式编写,例如:

    1
    2
    3
    >>> n = 4
    >>> [i + n for i in range(10)]
    [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

    是的,这是不一样的,但我从来没有看到过需要在列表中生成一组lambda函数的原因。在其他语言中可能有意义,但python不是haskell(或lisp,或…)

    Please note that we can use lambda and still achieve the desired
    results in this way :

    1
    2
    3
    >>> fs = [(lambda n,i=i: i + n) for i in range(10)]
    >>> fs[3](4)
    7

    编辑:

    在一些情况下lambda是有用的,例如,在Pyqt应用程序中连接信号时,它通常很方便,如下所示:

    1
    2
    w = PyQt4.QtGui.QLineEdit()
    w.textChanged.connect(lambda event: dothing())

    只要执行w.textChanged.connect(dothing)操作,就会用一个额外的event参数调用dothing方法并导致错误。使用lambda意味着我们可以整齐地删除参数,而不必定义包装函数。


    我发现lambda对于执行相同但不同情况的函数列表很有用。就像Mozilla的复数规则。

    1
    2
    3
    4
    5
    6
    7
    8
    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_1plural_rule_2等函数名也不太好,当您依赖于变量函数ID时,您需要eval()


    使用lambda可以做的几乎任何事情都可以在命名函数或列表和生成器表达式中做得更好。

    因此,在大多数情况下,您应该只是处于基本任何情况下的其中一个(除了在交互解释器中编写的草稿代码)。


    我使用Python已经有几年了,我从未遇到过需要lambda的情况。事实上,正如本教程所述,这只是为了提高句法水平。


    lambda函数这是一种创建函数的非官僚主义方法。

    就是这样。例如,让我们假设您有自己的主函数,并且需要平方值。让我们看看传统方法和lambda方法:

    传统方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def main():
    ...
    ...
    y = square(some_number)
    ...
    return something

    def square(x):
        return x**2

    拉姆达之道:

    1
    2
    3
    4
    5
    def main():
    ...
    square = lambda x: x**2
    y = square(some_number)
    return something

    看到区别了吗?

    lambda函数与列表非常匹配,比如列表理解或映射。事实上,列表理解这是一种用lambda表达自己的"Python式"方式。前任:

    1
    2
    3
    >>>a = [1,2,3,4]
    >>>[x**2 for x in a]
    [1,4,9,16]

    让我们看看语法的每个元素意味着什么:

    [] :"Give me a list"

    x**2 :"using this new-born function"

    for x in a:"into each element in a"

    很方便啊?创建这样的函数。让我们用lambda重写它:

    1
    2
    3
    >>> square = lambda x: x**2
    >>> [square(s) for x in a]
    [1,4,9,16]

    现在让我们使用map,它是相同的,但是语言更加中性。映射采用2个参数:

    (i)一个功能

    (ii)不可撤销的

    并给出一个列表,其中每个元素都是应用于iterable的每个元素的函数。

    因此,使用地图,我们可以:

    1
    2
    >>> a = [1,2,3,4]
    >>> squared_list = map(lambda x: x**2, a)

    如果您掌握了lambda和映射,那么您将能够以一种简洁的方式处理数据。lambda函数既不模糊,也不去除代码的清晰度。不要把困难的东西和新的东西混为一谈。一旦你开始使用它们,你会发现它非常清楚。


    我不能谈论Python对lambda的特定实现,但一般来说,lambda函数确实很方便。它们是功能编程的核心技术(甚至可能是技术),在面向对象的程序中也非常有用。对于某些类型的问题,它们是最好的解决方案,所以当然不应该忘记!

    我建议您阅读一下闭包和map函数(链接到python文档,但它存在于几乎所有支持函数构造的语言中)来了解它为什么有用。


    在我看来,lambda的一个好处是,它是一种将简单形式的评估推迟到需要值的方式。让我解释一下。

    许多库例程都是这样实现的:它们允许某些参数是可调用的(lambda就是其中之一)。其思想是,实际值只在使用时(而不是调用时)计算。一个(人为的)例子可能有助于说明这一点。假设您有一个将要记录给定时间戳的例程。您希望该例程使用当前时间减去30分钟。你可以这样称呼它

    1
    log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))

    现在假设只在某个事件发生时调用实际函数,并且您希望仅在此时计算时间戳。你可以这样做

    1
    log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))

    假设log_timestamp可以处理这样的可调用文件,它将在需要时对其进行评估,此时您将得到时间戳。

    当然,也有其他方法可以做到这一点(例如,使用operator模块),但我希望我已经表达了这一点。

    更新:这里是一个更具体的现实世界的例子。

    更新2:我认为这是一个被称为thunk的例子。


    lambda实际上是非常强大的结构,源于函数式编程的思想,在不久的将来,它绝不会轻易地被修改、重新定义或删除。它们帮助您编写更强大的代码,因为它允许您将函数作为参数传递,从而将函数作为头等公民的概念。

    lambda确实容易混淆,但是一旦获得了可靠的理解,您就可以编写干净、优雅的代码,如下所示:

    1
    squared = map(lambda x: x*x, [1, 2, 3, 4, 5])

    上面的代码行返回列表中数字的平方列表。当然,你也可以这样做:

    1
    2
    3
    4
    def square(x):
        return x*x

    squared = map(square, [1, 2, 3, 4, 5])

    很明显,前一个代码更短,如果您只打算在一个地方使用map函数(或任何将函数作为参数的类似函数),那么这一点尤其适用。这也使得代码更加直观和优雅。

    另外,正如@david zaslavsky在他的回答中提到的,列表理解并不总是可行的,特别是如果您的列表必须从一些模糊的数学方法中获取值。

    从一个更实际的角度来看,lambdas最近对我来说最大的优势之一是在GUI和事件驱动编程方面。如果你看一下Tkinter中的回调,它们所作为的参数就是触发它们的事件。例如。

    1
    2
    3
    4
    5
    def define_bindings(widget):
        widget.bind("<Button-1>", do-something-cool)

    def do-something-cool(event):
        #Your code to execute on the event trigger

    如果你有一些论点要通过呢?简单到传递两个参数来存储鼠标单击的坐标。您可以很容易地这样做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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

    现在你可以说这可以用全局变量来实现,但是你真的想为内存管理和泄漏担心吗,特别是当全局变量只在一个特定的地方使用的时候?那只是糟糕的编程风格。

    总之,羔羊是可怕的,不应该被低估。尽管Python羊羔和Lisp羊羔不同(它们更强大),但是你可以用它们做很多神奇的事情。


    如上所述,python中的lambda运算符定义了一个匿名函数,而python中的函数是闭包。重要的是不要将闭包的概念与运算符lambda混淆,lambda只是它们的语法美沙酮。

    几年前我开始使用Python时,我经常使用lambda,认为它们很酷,还有列表理解。但是,我写了一个用python编写的大网站,需要维护,大约有几千个功能点。我从经验中了解到,lambda可以使用原型,但是除了节省一些键斯托克(有时不提供)之外,对于内联函数(称为闭包)什么都不提供。

    基本上,这可以归结为几点:

    • 阅读使用有意义的名称显式编写的软件更容易。根据定义,匿名闭包不能有一个有意义的名称,因为它们没有名称。出于某种原因,这种简洁性似乎也会影响lambda参数,因此我们经常看到类似lambda x:x+1的例子。
    • 更容易重用命名的闭包,因为当有名称引用它们时,名称可以多次引用这些闭包。
    • 更容易调试使用命名闭包而不是lambda的代码,因为名称将出现在回溯和错误周围。

    这就足够把它们聚集起来并将它们转换为命名的闭包了。然而,我对匿名关闭还有两种怨恨。

    第一种怨恨就是它们只是另一个不必要的关键词,把语言搞得一团糟。

    第二个怨恨是更深层次的,在范式层面上,我不喜欢他们提倡一种函数式编程风格,因为这种风格比消息传递、面向对象或过程式要灵活得多,因为lambda演算并不是图灵完备的(幸运的是,在python中,即使在内部,我们仍然可以突破这种限制λ)我觉得兰伯斯提倡这种风格的原因是:

    • 有一个隐式的返回,即它们似乎"应该"是函数。

    • 它们是另一种更明确、更可读、更可重用和更通用的机制(方法)的替代状态隐藏机制。

    我努力地编写lambda-free-python,并在看到的时候删除lambda。我认为如果没有lambda,python会是一种更好的语言,但这只是我的观点。


    一般来说,lambda与函数式编程风格有着深刻的联系。你可以通过对一些数据应用一个函数,并合并结果来解决问题,这是谷歌用来实现其大部分算法的想法。

    以函数式编程方式编写的程序很容易并行化,因此在现代多核机器中变得越来越重要。总之,不,你不应该忘记他们。


    首先恭喜你找到了lambda。在我看来,这是一个非常强大的结构。如今向函数式编程语言发展的趋势无疑是一个指标,它既不应被避免,也不会在不久的将来被重新定义。

    你只需要稍微改变一下想法。我相信很快你就会喜欢的。但如果只处理python,就要小心。因为lambda不是一个真正的闭包,它不知何故被"破坏":Pythonlambda被破坏了。


    我使用lambda来避免代码重复。它将使函数易于理解如:

    1
    2
    3
    4
    5
    6
    7
    8
    def a_func()
      ...
      if some_conditon:
         ...
         call_some_big_func(arg1, arg2, arg3, arg4...)
      else
         ...
         call_some_big_func(arg1, arg2, arg3, arg4...)

    我把它换成临时的lambda

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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)

    我是一个python初学者,所以为了对lambda有一个清晰的概念,我将它与"for"循环进行了比较,以提高效率。这是代码(python 2.7)-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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'm just beginning Python and ran head first into Lambda- which took me a while to figure out.

    注意,这不是对任何事情的谴责。每个人都有一套不同的东西,不容易得到。

    Is lambda one of those 'interesting' language items that in real life should be forgotten?

    不。

    I'm sure there are some edge cases where it might be needed, but given the obscurity of it,

    它并不晦涩。我工作过的两个团队,每个人都一直使用这个功能。

    the potential of it being redefined in future releases (my assumption based on the various definitions of it)

    除了几年前修复了闭包语义之外,我还没有看到在Python中重新定义它的严肃建议。

    and the reduced coding clarity - should it be avoided?

    如果你使用得当,情况就不那么清楚了。相反,拥有更多的语言结构可以提高清晰度。

    This reminds me of overflowing (buffer overflow) of C types - pointing to the top variable and overloading to set the other field values...sort of a techie showmanship but maintenance coder nightmare..

    lambda类似于缓冲区溢出?真的。如果你认为它是一个"维护噩梦",我无法想象你是如何使用lambda的。


    使用lambdas的一个有用的例子是提高长列表理解的可读性。在这个例子中,loop_dic是"清晰"的缩写,但假设loop_dic非常长。如果只使用包含i的普通值,而不是该值的lambda版本,则会得到NameError

    1
    >>lis=["name""peter<hr><P>我今天开始读大卫梅尔茨的书《用python进行文本处理》。虽然他对lambda的描述相当简洁,但第一章中的例子加上附录A中的解释,使他们为我跳下了页面(最后),我突然明白了他们的价值。这并不是说他的解释对你有用,而我仍处于发现阶段,因此除了以下内容外,我不会尝试在这些回答中添加其他内容:我是Python的新手我是新手兰伯斯对我来说是一场斗争现在我读了mertz,我认为我得到了它们,并且我认为它们非常有用,因为我认为它们允许一种更清洁的编程方法。</P><P>他复制了Python的禅,其中一行很简单,而不是复杂。作为一个非OOP编程人员,我一直认为这很简单,因为我一直在用lambda阅读代码(直到上周才列出理解)。.我今天终于意识到,实际上这些特性使代码比另一种方法更易于阅读和理解,后者总是某种类型的循环。我还意识到,和财务报表一样,python不是为新手用户设计的,而是为想要接受教育的用户设计的。我不敢相信这种语言有多强大。当我(终于)领悟到lambdas的目的和价值时,我想撕掉大约30个程序,在适当的时候重新安装lambdas。</P><hr><P>我可以给你一个例子,我实际上需要认真的lambda。我正在制作一个图形程序,在该程序中,用户右键单击一个文件,并将其指定为三个选项之一。事实证明,在Tkinter(我写这个的GUI接口程序)中,当有人按下一个按钮时,它不能被分配给接受参数的命令。因此,如果我选择了其中一个选项,并希望我选择的结果是:</P>[cc lang="python"]print 'hi there'

    那就没什么大不了的了。但是如果我需要我的选择来有一个特定的细节呢?例如,如果我选择选项A,它会调用一个函数,该函数接受一些依赖于选项A、B或C的参数,tkinter不支持这种情况。拉姆达是唯一能避开这一切的选择。


    我使用lambda创建包含参数的回调。在一行中编写lambda比编写执行相同功能的方法更干净。

    例如:

    1
    2
    3
    4
    import imported.module

    def func():
        return lambda: imported.module.method("foo","bar")

    与之相反:

    1
    2
    3
    4
    5
    6
    import imported.module

    def func():
        def cb():
            return imported.module.method("foo","bar")
        return cb


    我经常使用它,主要是作为空对象或将参数部分绑定到函数。

    以下是示例:

    要实现空对象模式:

    1
    2
    3
    4
    {
        DATA_PACKET: self.handle_data_packets
        NET_PACKET: self.handle_hardware_packets
    }.get(packet_type, lambda x : None)(payload)

    对于参数绑定:

    假设我有以下API

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def dump_hex(file, var)
        # some code
        pass

    class X(object):
        #...
        def packet_received(data):
            # some kind of preprocessing
            self.callback(data)
        #...

    然后,当我不想快速将接收到的数据转储到文件时,我会这样做:

    1
    2
    3
    4
    dump_file = file('hex_dump.txt','w')
    X.callback = lambda (x): dump_hex(dump_file, x)
    ...
    dump_file.close()

    lambda是过程构造函数。您可以在运行时合成程序,尽管python的lambda不是很强大。注意,很少有人理解这种编程。