Python中lambda和常规函数有什么区别?

47
我对 lambda 函数和普通函数(用 def 定义)之间在Python层面上的区别很感兴趣。(我知道程序员使用它们和何时使用每个函数有什么区别。)
>>> def a():
    return 1

>>> b = lambda: 1
>>> a
<function a at 0x0000000004036F98>
>>> b
<function <lambda> at 0x0000000004031588>

正如我们所看到的 - Python 知道 b 是一个lambda函数,而a是一个普通函数。为什么会这样呢?它们在Python中有什么区别?


1
Python在运行时支持创建匿名函数(即不绑定到名称的函数),使用一个称为“lambda”的结构。你可以在http://www.secnetix.de/olli/Python/lambda_functions.hawk上查看它。这意味着它不会给你函数的名称。 - Manoj Suryawanshi
9
这个问题中哪些方面让你认为提问者不知道那件事情? - Marcin
@Marcin:正如Simeon Visser在答案中所示的示例,您可以了解到OP不知道函数的名称。 - Manoj Suryawanshi
6个回答

39

它们是相同的类型,因此它们被同样对待:

>>> type(a)
<type 'function'>
>>> type(b)
<type 'function'>

Python同样知道b是一个lambda函数,并将其设置为函数名称:

>>> a.func_name
'a'
>>> b.func_name
'<lambda>'
换句话说,它影响函数的名称,但就Python而言,两者都是函数,这意味着它们可以以大多数相同的方式使用。请参见mgilson在下面的评论中关于函数和lambda函数在pickling方面的重要区别。

37
无法将 lambda 函数序列化(pickled),因为它们没有关联的(独特)名称。这就是为什么不能将其与 multiprocessing 等一起使用,这在某些情况下可能会导致 PicklingError 错误。 - mgilson
7
另外值得指出的是,lambda 是一个表达式而 def 是一个语句。由于 lambda 是一个表达式,它只能包含其他表达式(不允许使用语句)--尽管这更多地是程序员层面上的问题,而不是“为什么Python需要跟踪这种区别”的问题。 - mgilson
2
Lambda表达式可以作为表达式使用,而传统函数则不能;但我想你已经知道了这一点。 - Burhan Khalid
考虑到内部 ab 是相同类型,即都是 function,我认为它们之间没有性能优劣之分? - Jens

15
唯一的区别在于(a) lambda 函数体只能由一个表达式组成,该表达式的结果将从创建的函数中返回;(b) lambda 表达式是一个可评估为函数对象的表达式,而 def 语句没有值,它创建一个函数对象并将其绑定到一个名称。
在所有其他方面,它们产生相同的对象 - 相同的作用域和捕获规则适用。(不重要的差异是 lambda 创建的函数具有默认的 func_name"<lambda>"。这可能会影响到某些奇特情况下的操作,例如对函数进行 pickle 的尝试)。

3

lambdadef都创建相同类型的函数 - 它们具有相同的元数据和功能。它们的技术差异在于语法:

  • lambda是一个产生函数的表达式。
  • def是一个产生函数的语句。

这是决定它们如何使用的关键。其他明显的差异只是来自lambda/def可以捕获的信息。

>>> def def_func(): pass
>>> lambda_func = lambda: None
>>> type(def_func) == type(lambda_func)
True
用法:表达式 vs 语句

lambda更灵活,因为表达式可以成为更多的语言结构的一部分。

#                v--------------v arguments must be expressions
sort(values, key=lambda x: abs(x))

相比之下,def 更强大,因为它可以包含更多的语言结构。
def encode(num, base):
    while num:   # statements must be inside statements
        num, bit = divmod(num, base)
        yield bit

这些差异直接源于它们分别是表达式和语句。Python没有特殊规则来决定在哪里可以使用 lambda/def


无名的<lambda>函数

认为 lambdadef 对应不同类型的函数的主要原因是 “元数据”: lambda 经常被称为 “匿名函数”,并且奇妙地总是产生一个 function <lambda>。 其他特点包括 “lambda函数无法被 pickled”,最近typing也对 lambda “不起作用”。

这是因为与 def 语法相比,lambda 语法没有办法指定名称、类型注释和类似内容。因此,Python 简单地为其填充合理的默认值:名称变成了 <lambda>,注释留空。

>>> identity = lambda a: a
>>> identity.__qualname__
'<lambda>'
>>> identity.__annotations__
{}

自从<lambda>不是一个有效的标识符,使用这个元数据来查找函数的所有内容,尤其是pickle都会失败。
然而,这并不使该函数成为“匿名函数”类型。可以修补元数据以插入def提供的内容。
>>> identity.__qualname__ = identity.__name__ = 'identity'
>>> identity
<function __main__.identity(a)>

当然,在某一点上,可以直接使用def

1

首先考虑两者之间的差异。

Lambda函数:是运算符,可以有任意数量的参数,但只能有一个表达式。它不能包含任何语句,并返回一个函数对象,可以分配给任何变量。它们可以在创建它们的块中使用。

def函数:函数帮助将我们的程序分解成更小和模块化的块。随着我们的程序越来越大,函数使其更有组织和可管理性。它们可以在任何地方调用和使用。

通过以下示例,您可以更清楚地了解两者之间的区别。

定义函数

    def add(a,b):
      return a+b
    print(add(4,5))

定义一个lambda函数。
    add = lambda x, y : x + y 
    print(add(4,5))

1
谢谢@Saurabh,但我的问题是Python的区别是什么,而不是如何使用它。 - slallum

0

Lambda是一种内联函数,我们可以在没有函数名称的情况下执行任何功能。当我们将其用作高阶函数的参数时,它非常有用。例如:一个接受其他函数作为参数的函数。

函数定义示例:

>>> def func(a, b):
    return a * b

>>> func(2,3)
6
>>> type(func)
<class 'function'>
>>> func
<function func at 0x034B6E88>

Lambda表达式的示例:

>>> multiply = lambda a, b: a * b
>>> multiply(2, 3)
6
>>> type(multiply)
<class 'function'>
>>> multiply
<function <lambda> at 0x034B6ED0>

两者返回相同的输出值,只是返回的对象不同。函数使用“func”名称,Lambda使用“lambda”名称。


2
谢谢你的回答,但请注意我知道程序员使用它们的区别以及何时使用它们(正如我在问题中所说)。 - slallum

0

lambda 创建一个匿名函数。这个想法来自于函数式编程语言。通过这种方式,您可以创建并将函数传递给其他函数,例如 mapfilter。(请参见此处
您也可以将普通函数传递给这些函数,但由于它们大多数是简单的,并且不在任何其他地方使用,因此通过定义新函数的整个过程是不方便的。

以此为例:

>>> a = [1, 2, 3, 4]
>>> print map( lambda x : x*2 + 1, a )
[3, 5, 7, 9, 11]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接