【问题标题】:Function definitions vs Lambda expression函数定义与 Lambda 表达式
【发布时间】:2012-12-13 05:12:24
【问题描述】:

鉴于这两个 sn-ps:

def sex (code):
    return {'m': 'masculino', 'f': 'femenino', '': 'ignorado'} [code]

sex = lambda code: {'m': 'masculino', 'f': 'femenino', '': 'ignorado'} [code]

实际的区别是什么?他们有不同的行为吗?

最重要的是:一个比另一个更受欢迎吗?

我问这个问题,因为我在这个论坛 (python3 - learning about searching, this very simple example does not work right) 中的一个回答提供了两种可能性,但被另一个用户截断(“修订”),删除了 lambda 术语。修改的原因是最后一个选项(lambda 表达式)比函数定义更糟糕。这让我想知道:

为什么 lambda 表达式比函数定义更糟糕?尤其是像这样的简单表达式。

【问题讨论】:

    标签: python


    【解决方案1】:

    返回相同内容的 lambda 和 def 在功能上没有区别。它们完全相同,并且具有相同的字节码。

    >>> def sex (code):
    ...     return {'m': 'masculino', 'f': 'femenino', '': 'ignorado'} [code]
    >>> sex2 = lambda code: {'m': 'masculino', 'f': 'femenino', '': 'ignorado'} [code]
    >>> sex.__code__.co_code == sex2.__code__.co_code
    True
    

    我会说,在一般意义上说任何一种编写函数的方式都“更糟”是错误的。但是,在您的示例中,def 版本更好。原因是,通常 lambdas 的目的是在表达式中简洁地编写简短的匿名函数。做name = lambda: ... 没有任何意义。如果您要立即为其命名,则没有理由定义匿名函数。

    lambdas 的重点是你可以做someFuncRequiringCallback(lambda x: x+1),在这种情况下你不想给函数一个名字或将它用于除这种情况之外的任何事情。如果您确实想在多个上下文中使用一个函数,只需使用常规 def 定义它。

    【讨论】:

    • 我能想到一个小区别:print sex.__name__, sex2.__name__.
    • @DSM:这与def foo: return 1def bar: return 1 没有什么不同。这两个功能还是一样的。
    • 由于函数具有相同的代码,我完全同意没有功能差异,但有几次我检查过__name__,我不能用 lambda . YMMV。
    【解决方案2】:

    都是一样的,查看反汇编的python字节码

    >>> def sex1 (code):
        return {'m': 'masculino', 'f': 'femenino', '': 'ignorado'} [code]
    
    >>> sex2 = lambda code: {'m': 'masculino', 'f': 'femenino', '': 'ignorado'} [code]
    >>> dis.dis(sex1)
      2           0 BUILD_MAP                3
                  3 LOAD_CONST               1 ('masculino')
                  6 LOAD_CONST               2 ('m')
                  9 STORE_MAP           
                 10 LOAD_CONST               3 ('femenino')
                 13 LOAD_CONST               4 ('f')
                 16 STORE_MAP           
                 17 LOAD_CONST               5 ('ignorado')
                 20 LOAD_CONST               6 ('')
                 23 STORE_MAP           
                 24 LOAD_FAST                0 (code)
                 27 BINARY_SUBSCR       
                 28 RETURN_VALUE        
    >>> dis.dis(sex2)
      1           0 BUILD_MAP                3
                  3 LOAD_CONST               1 ('masculino')
                  6 LOAD_CONST               2 ('m')
                  9 STORE_MAP           
                 10 LOAD_CONST               3 ('femenino')
                 13 LOAD_CONST               4 ('f')
                 16 STORE_MAP           
                 17 LOAD_CONST               5 ('ignorado')
                 20 LOAD_CONST               6 ('')
                 23 STORE_MAP           
                 24 LOAD_FAST                0 (code)
                 27 BINARY_SUBSCR       
                 28 RETURN_VALUE    
    

    即使它们都具有相同的类型

    >>> type(sex1)
    <type 'function'>
    >>> type(sex2)
    <type 'function'>
    

    【讨论】:

      【解决方案3】:

      除了BrenBarn's excellent answer中提供的信息之外,你会发现很多Python程序员坚持总是使用def而不是lambda,所以我将尝试解释为什么会这样。

      它基本上归结为Zen of Python的以下行:

      应该有一种——最好只有一种——明显的方法。

      这是在Guido van Rossum's post about this issue中引用的(Guido是Python的创造者):

      为什么要放弃 lambda?大多数 Python 用户对 Lisp 或 Scheme 不熟悉,因此名称令人困惑;此外,还有一个普遍的误解,即 lambda 可以做嵌套函数不能做的事情——在我向她展示没有区别之后,我仍然记得 Laura Creighton 的 Aha!-erlebnis!即使有一个更好的名字,我认为将这两个选择并排只需要程序员考虑做出与他们的程序无关的选择;没有选择可以简化思考过程。此外,一旦 map()、filter() 和 reduce() 消失了,就没有很多地方需要编写非常短的局部函数了。想到了 Tkinter 回调,但我发现回调通常应该是一些带有状态的对象的方法(玩具程序除外)。

      【讨论】:

      • 感谢您的回答以及 Guido 帖子的链接。很有意思。我自己也经历过:自从我们从 py2.7 迁移到 py3.2 后,大多数 map()、filter() 等表达式都变成了像 (f(x) for x in l if x) 这样的生成器。尽管如此,我很高兴我们仍然有 lambda。
      【解决方案4】:

      简单的 lambda 不一定比嵌套函数差(不,这两个示例之间除了语法没有区别),但这种特殊情况可以更简单:

      sex = {'m': 'masculino', 'f': 'femenino', '': 'ignorado'}
      

      然后你使用sex.__getitem__

      【讨论】:

        【解决方案5】:

        它们具有相同的行为,但主要区别在于 lambda 是一个表达式,因此不能包含语句。只要使用得当,lambda 不一定比函数定义差。然而,它们经常被用来编写单行函数,只是因为它们可以,即使它使代码实际上无法阅读。例如,考虑以下情况:

        sortfilter = lambda a, b, c: sorted(filter(lambda i: i % 2, (i for i in a if i in b)), key=lambda v: c.get(v, v)))
        

        可以用单行 lambda 编写,但这是一个非常糟糕的主意!

        【讨论】:

          【解决方案6】:

          它有助于区分事物。如果我要定义一个函数,我将从 def 开始,但是在该函数内部我通常会使用 lambda。

          这与用英语写作的概念相同。如果引用正在引用引用,您将需要更改嵌套引用的外观。括号也是如此。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-09-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多