-->

这是更优选的是使用在Python:lambda函数或嵌套函数(“高清”)?(Which is mor

2019-06-21 05:22发布

我主要使用lambda函数,但有时使用似乎提供相同的行为嵌套函数。

下面是一些简单的例子,他们在功能上做同样的事情,如果任一被另一个函数中发现:

lambda函数

>>> a = lambda x : 1 + x
>>> a(5)
6

嵌套函数

>>> def b(x): return 1 + x

>>> b(5)
6

在那里使用了另一种优势? (性能?可读性?局限性?一致性?等等)

它甚至关系呢? 如果它不那么这是否违反Python化原则:

“应该有一个和做最好只有一个显而易见的方式” 。

Answer 1:

如果您需要将分配lambda到一个名字,使用def代替。 def s为一个分配正义的语法糖,所以结果是一样的,他们有很多更灵活,更具有可读性。

lambda s时,可以用于使用一次,扔掉它不会有一个名字的功能。

然而,这种使用情况是非常罕见的。 你很少需要传阅匿名函数对象。

该内建map()filter()需要功能的对象,但是列表解析发电机表达式通常比那些功能更好的可读性和可覆盖所有的用例,而无需lambda表达式。

对于情况下,你真的需要一个小的函数对象,你应该使用operator模块的功能,如operator.add而不是lambda x, y: x + y

如果您还需要一些lambda不是盖的,你可能会考虑写一个def ,只是要更具可读性。 如果函数比那些在更复杂的operator模块, def是可能会更好。

所以,真正的世界好lambda使用情况是非常罕见的。



Answer 2:

实事求是地讲,我有两点不同:

第一个是关于他们做什么,他们返回的内容:

  • 高清是一个不返回任何东西,会在本地命名空间中的名字“这样的关键字。

  • 拉姆达是返回一个函数对象,并不会创建本地命名空间中的名字“这样的关键字。

因此,如果你需要调用一个函数,函数对象,要做到这一点在Python代码一行是用拉姆达的唯一途径。 有与高清没有等价。

在一些框架其实这是很常见的; 例如,我用扭曲了很多,所以做这样的事情

d.addCallback(lambda result: setattr(self, _someVariable, result))

是相当普遍的,而且更简洁与lambda表达式。

第二个区别是什么实际功能是允许这样做。

  • 与“高清”所定义的函数可以包含任何Python代码
  • 与“拉姆达”定义的函数来评估一个表达式,因此不能包含诸如打印,import语句,提高,...

例如,

def p(x): print x

按预期工作,而

lambda x: print x

是一个SyntaxError。

当然,也有变通方法-替代printsys.stdout.write ,或import__import__ 。 但通常你最好在这种情况下,一个功能去。



Answer 3:

在这次采访中,吉多·范罗苏姆说,他希望他不会让“拉姆达”到Python的:

问:什么功能的Python是你最高兴?

有时候,我一直过快地接受捐款,后来意识到这是一个错误。 一个示例将是一些的功能编程的功能,如lambda函数。 拉姆达是一个关键字,可以让你创建一个小型匿名函数; 内置功能,例如地图,过滤,并降低运行在一个序列类型的函数,例如为列表。

在实践中,并没有变成那么好。 Python的只有两个范围:本地和全局。 这使得编写lambda函数痛苦的,因为你经常要访问在定义拉姆达变量的作用域,但你不能因为两个范围的。 有解决的办法,但它是一个杂牌的东西。 通常,它似乎更容易在Python只使用一个for循环,而不是用lambda函数乱搞的。 地图和朋友们工作得很好,只有当已经有一个内置的功能,你想要做什么。

恕我直言,Iambdas可以方便有时,但通常是在可读性为代价的方便。 你能告诉我这是什么呢:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

我写的,我花了一分钟的数字出来。 这是从项目欧拉 - 因为我讨厌的破坏者,但它在0.124秒运行,我不会说这问题:)



Answer 4:

对于n = 1000这里是调用一个函数VS拉姆达的一些timeit的:

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop


Answer 5:

我同意nosklo的建议是:如果你需要给该功能的名称,使用def 。 我保留lambda功能在那里我只是路过的代码简短摘要给另一个函数,如情况:

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )


Answer 6:

性能:

创建具有功能lambda是比创造它稍快 def 。 所不同的是,由于def创造当地人表中的名项。 将得到的函数具有相同的执行速度。


可读性:

拉姆达函数在某种程度上对于大多数Python用户的可读性,而且很多在某些情况下更为简洁。 考虑使用非功能到功能程序转换:

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

正如你所看到的, lambda的版本是在这个意义上,你只需要添加短,“容易” lambda v:原来的非功能性版本转换为功能版本。 这也是很多更简洁。 但要记住,很多Python用户的将由lambda语法相混淆,让你在长度和复杂性真正失去什么可能来自同伴编码器来获得回混乱。


限制:

  • lambda函数只能使用一次,除非分配给一个变量名。
  • lambda分配给变量名函数没有优势def功能。
  • lambda函数可以是困难的或不可能的泡菜。
  • def功能的名字必须仔细选择,以合理地描述的和独特的或至少在范围其他未使用的。

一致性:

Python的大多避免了赞成的程序和简单的客观语义的函数式编程约定。 该lambda操作员站直接的对比这种偏见。 此外,作为替代已经流行def ,则lambda功能增加了多样性,你的语法。 有些人会认为不太一致。


预先存在的功能:

如其他人所指出的,许多用途lambda在现场可通过的部件代替operator或其他模块。 例如:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

使用预先存在的功能,可以使代码在很多情况下更具有可读性。


在Python化原则:“应该有一个和最好只有一个显而易见的做路”

这是类似于单一数据源学说。 不幸的是,单显而易见的路到做它的一贯原则更多的Python的渴望的愿望,而不是一个真正的指导原则。 考虑Python中非常强大的阵列内涵。 它们在功能上等同于mapfilter功能:

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambdadef是相同的。

这是见仁见智的问题,但我要说的用于常规用途不显着破坏任何东西Python语言,任何事情都是“Python化”就够了。



Answer 7:

拉姆达的主要用途一直是简单的回调功能,并在地图,减少,过滤器,它需要一个函数作为参数。 随着列表内涵成为常态,如果作为添加允许的:

x = [f for f in range(1, 40) if f % 2]

很难想象,在日常使用中使用拉姆达的一个真实的案例。 其结果是,我会说,避免拉姆达创造嵌套函数。



Answer 8:

lambda表达式的一个重要的限制是,它们不能包含除表达什么。 这几乎是不可能的lambda表达式产生除了微不足道的副作用任何东西,因为它不能有任何接近富人的身体作为def “编辑功能。

话虽这么说,Lua的影响了我的编程风格向大量使用匿名函数,和我垃圾我的代码使用它们。 最重要的是,我倾向于认为有关的map / reduce抽象运营商的方式,我不认为list解析或发电机,几乎一样,如果我使用这些运营商明确的推迟实施的决定。

编辑:这是一个很老的问题,我对此事的看法发生了变化,一些。

首先,我强烈偏压分配lambda表达式的变量; 如Python已经只是一个特殊的语法(提示, def )。 除此之外,多为拉姆达的用途,即使他们没有得到一个名字,已经预定义的(和更有效)的实现。 例如,所讨论的示例可以缩写为只是(1).__add__ ,而不需要将其包装在一个lambdadef 。 许多其他常见的用途可以得到满意的一些组合operatoritertoolsfunctools模块。



Answer 9:

虽然与其他答案同意,有时它更具有可读性。 这里有一个例子,其中lambda就派上用场了,在使用情况下,我不断遇到一个N维的defaultdict
下面是一个例子:

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

我觉得这不是创建一个更具可读性def的第二个维度。 这甚至更高的尺寸更显著。



Answer 10:

更优选的:lambda函数或嵌套函数( def )?

有一个优势,使用的λ通过常规功能(它们在表达式创建的),和若干缺点。 出于这个原因,我更喜欢与创建函数def关键字,而不是用lambda表达式。

第一点 - 它们是相同类型的对象

一个lambda产生相同类型的对象作为常规函数

>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
... 
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True

由于lambda表达式的功能,他们是第一类对象。

这两个lambda表达式和函数:

  • 可以绕过作为参数(同常规功能)
  • 当外部函数内创建变得过该外功能当地人的封闭

但是lambda表达式是,默认情况下,缺少一些东西,其功能通过全功能定义语法得到。

甲兰巴的__name__'<lambda>'

Lambda表达式是匿名的功能,毕竟,所以他们不知道自己的名字。

>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'

因此拉姆达的不能以编程方式在他们的命名空间中抬起头来。

这限制了某些事情。 例如, foo可抬头用序列代码,而l不了:

>>> import pickle
>>> pickle.loads(pickle.dumps(l))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fbbc0464e18>: 
attribute lookup <lambda> on __main__ failed

我们可以查找foo就好了-因为它知道自己的名字:

>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>

Lambda表达式没有注释和文档字符串无

基本上,lambda表达式没有记载。 让我们来重写foo是更好地记录:

def foo() -> int:
    """a nullary function, returns 0 every time"""
    return 0

现在,foo有着和文档:

>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:

foo() -> int
    a nullary function, returns 0 every time

然而,我们没有相同的机制来提供相同的信息lambda表达式:

>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda (...)

但是,我们可以破解他们:

>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda ) -> in
    nullary -> 0

但也有可能是一些错误搞乱的帮助输出,虽然。

Lambda表达式只能返回一个表达式

Lambda表达式无法返回复杂的语句,只是表情。

>>> lambda: if True: 0
  File "<stdin>", line 1
    lambda: if True: 0
             ^
SyntaxError: invalid syntax

表达式可以固然是相当复杂的,如果你非常努力,你也许可以做到与拉姆达相同,但增加的复杂性更是一个不利的编写清晰的代码。

我们使用Python的清晰度和可维护性。 lambda表达式的过度使用可以工作对抗。

为lambda表达式的唯一优点:可以在一个单一表达式来创建

这是唯一可能的上涨空间。 既然你可以用表达式创建一个lambda,你可以在函数调用内创建它。

创建一个函数调用内部的功能避免了(便宜的)名称查找与一个其它地方产生。

然而,由于Python是严格评估,没有其他的性能增益,从避免名称查找这样一边。

对于一个非常简单的表情,我可能会选择一个lambda。

我也倾向于做交互式Python时使用lambda表达式,以避免多行的时候人会做。 我用下面这种编码格式的时,我想打电话时的参数传递给构造timeit.repeat

import timeit

def return_nullary_lambda(return_value=0):
    return lambda: return_value

def return_nullary_function(return_value=0):
    def nullary_fn():
        return return_value
    return nullary_fn

现在:

>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304

我相信上面的微小的时间差可以归因于在名称查找return_nullary_function -注意,这是微不足道的。

结论

Lambda表达式是良好的,你要在有利于使奇异点减少的代码行非正式场合。

Lambda表达式是坏的,你需要清晰的代码编辑器谁以后还会来,尤其是在他们不平凡的情况下,更正式的场合。

我们知道我们应该给我们的对象好名字。 我们怎样才能做到这一点时,对象没有名字?

基于这些原因,我更喜欢用创建函数def ,而不是与lambda



Answer 11:

如果你只是要在lambda分配给一个变量在局部范围内,你不妨使用高清,因为它是更具可读性和可在未来更容易扩展:

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

要么

def fun(a, b): return a ** b # more readable
map(fun, someList)


Answer 12:

因为我已经找到一个lambda表达式使用......在调试消息。

由于lambda表达式可以懒洋洋地评估你可以有这样的代码:

log.debug(lambda: "this is my message: %r" % (some_data,))

而不是可能是昂贵的:

log.debug("this is my message: %r" % (some_data,))

该进程,即使该调用调试不会产生因为当前的日志级别输出格式字符串。

当然,所描述的日志模块在使用中必须支持lambda表达式为“懒参数”(我的记录模块一样),它的工作。

同样的概念可以适用于懒惰评估的其他任何情况下,内容点播创造价值。

例如,这习俗三元运算符:

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

代替:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

与lambda表达式仅由条件选择的表达将被评估,而无需二者lambda表达式将被评估。

当然,你可以简单地使用功能,而不是lambda表达式,但对于短表达式lambda表达式是(C)精简。



Answer 13:

我同意nosklo。 顺便说一句,即使有使用一次,扔掉的功能,你们中的大多数只是想使用的东西从操作模块的时间。

EG:

你必须与此签名的函数:myFunction的(数据,回调函数)。

你想传递一个加2元的功能。

使用lambda:

myFunction(data, (lambda x, y : x + y))

在Python的方式:

import operator
myFunction(data, operator.add)

或者,当然,这是一个简单的例子,但有很多东西操作模块提供,包括列表和字典的项目制定者/吸气。 真是太爽了。



Answer 14:

  • 计算时间。
  • 功能没有名称。
  • 为了实现一个功能,很多使用的功能。

考虑一个简单的例子,

# CREATE ONE FUNCTION AND USE IT TO PERFORM MANY OPERATIONS ON SAME TYPE OF DATA STRUCTURE.
def variousUse(a,b=lambda x:x[0]):
    return [b(i) for i in a]

dummyList = [(0,1,2,3),(4,5,6,7),(78,45,23,43)]
variousUse(dummyList)                           # extract first element
variousUse(dummyList,lambda x:[x[0],x[2],x[3]]) # extract specific indexed element
variousUse(dummyList,lambda x:x[0]+x[2])        # add specific elements
variousUse(dummyList,lambda x:x[0]*x[2])        # multiply specific elements


Answer 15:

拉姆达是用于生成新的功能有用的:

def somefunc(x): return lambda y: x+y
f = somefunc(10)
f(2)
>>> 12
f(4)
>>> 14


Answer 16:

一个主要的区别是,你不能使用def内联函数,这在我看来是最方便的用例的lambda功能。 例如排序对象的列表时:

my_list.sort(key=lambda o: o.x)

因此,我建议保持使用lambda表达式的这类琐碎的操作,这也并不真正从命名功能,提供的自动文档中受益。



文章来源: Which is more preferable to use in Python: lambda functions or nested functions ('def')?