我主要使用lambda函数,但有时使用似乎提供相同行为的嵌套函数.
这里有一些简单的例子,如果在另一个函数中找到它们,它们在功能上做同样的事情:
Lambda函数
>>> a = lambda x : 1 + x >>> a(5) 6
嵌套功能
>>> def b(x): return 1 + x >>> b(5) 6
使用一个优于另一个是否有优势?(性能?可读性?限制?一致性?等)
它甚至重要吗?如果不这样做那就违反了Pythonic原则:
"应该有一种 - 最好只有一种 - 显而易见的方法".
nosklo.. 94
如果您需要将lambda
名称指定给名称,请使用def
替代名称.def
s只是赋值的语法糖,所以结果是一样的,它们更灵活,更易读.
lambda
s可以使用一次,扔掉没有名字的函数.
但是,这个用例非常罕见.您很少需要传递未命名的函数对象.
内置map()
和filter()
需要函数对象,但是列表推导和生成器表达式通常比那些函数更具可读性,并且可以覆盖所有用例,而不需要lambdas.
对于你真的需要一个小函数对象的情况,你应该使用operator
模块函数,operator.add
而不是lambda x, y: x + y
如果你仍然需要一些lambda
不被覆盖的东西,你可以考虑写一个def
,只是为了更具可读性.如果函数比operator
模块上的函数更复杂,def
则可能更好.
所以,现实世界的好用lambda
例非常罕见.
如果您需要将lambda
名称指定给名称,请使用def
替代名称.def
s只是赋值的语法糖,所以结果是一样的,它们更灵活,更易读.
lambda
s可以使用一次,扔掉没有名字的函数.
但是,这个用例非常罕见.您很少需要传递未命名的函数对象.
内置map()
和filter()
需要函数对象,但是列表推导和生成器表达式通常比那些函数更具可读性,并且可以覆盖所有用例,而不需要lambdas.
对于你真的需要一个小函数对象的情况,你应该使用operator
模块函数,operator.add
而不是lambda x, y: x + y
如果你仍然需要一些lambda
不被覆盖的东西,你可以考虑写一个def
,只是为了更具可读性.如果函数比operator
模块上的函数更复杂,def
则可能更好.
所以,现实世界的好用lambda
例非常罕见.
实际上,对我来说有两点不同:
第一个是关于他们做什么以及他们返回什么:
def是一个不返回任何内容的关键字,并在本地名称空间中创建"名称".
lambda是一个返回函数对象的关键字,不会在本地名称空间中创建"名称".
因此,如果你需要调用一个带有函数对象的函数,在一行python代码中执行该操作的唯一方法是使用lambda.没有与def相当的东西.
在某些框架中,这实际上很常见; 例如,我使用Twisted很多,所以做了类似的事情
d.addCallback(lambda result: setattr(self, _someVariable, result))
很常见,而且对lambdas更简洁.
第二个区别是关于允许实际功能的内容.
用'def'定义的函数可以包含任何python代码
用'lambda'定义的函数必须求值为表达式,因此不能包含print,import,raise等语句.
例如,
def p(x): print x
按预期工作,而
lambda x: print x
是一个SyntaxError.
当然,也有变通方法-代替print
用sys.stdout.write
,或import
用__import__
.但在这种情况下,通常你最好使用一个函数.
在这次采访中, Guido van Rossum说他希望他不要让'lambda'进入Python:
" 问:你最不满意Python的哪些特性?
有时候我太快接受了贡献,后来才意识到这是一个错误.一个例子就是一些函数编程功能,比如lambda函数.lambda是一个允许您创建小型匿名函数的关键字;内置函数(如map,filter和reduce)在序列类型(如列表)上运行函数.
在实践中,它并没有那么好.Python只有两个范围:本地和全局.这使得编写lambda函数变得很痛苦,因为你经常想要在定义lambda的范围内访问变量,但是由于这两个范围你不能.有一种解决方法,但它是一种kludge.通常,在Python中使用for循环而不是乱用lambda函数似乎更容易.地图和朋友只有在已有内置功能完成您想要的功能时才能正常工作.
恕我直言,Iambdas有时候很方便,但通常以牺牲可读性为代价.你能告诉我这是做什么的:
str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]
我写了它,我花了一分钟才弄明白.这是来自项目欧拉 - 我不会说哪个问题因为我讨厌剧透,但它在0.124秒内运行:)
对于n = 1000,这里有一个调用函数vs lambda的时间:
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
我同意nosklo的建议:如果你需要给这个函数命名,请使用def
.我保留lambda
函数用于我只是将一小段代码传递给另一个函数的情况,例如:
a = [ (1,2), (3,4), (5,6) ] b = map( lambda x: x[0]+x[1], a )
性能:
以创建一个功能lambda
是速度稍快比创建它def
.不同之处def
在于在locals表中创建了一个名称条目.结果函数具有相同的执行速度.
可读性:
对于大多数Python用户来说,Lambda函数的可读性稍差,但在某些情况下也更简洁.考虑从使用非功能性转换为功能性例程:
# 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)
使用预先存在的函数可以使代码在许多情况下更具可读性.
Pythonic原则:"应该有一个 - 最好只有一个 - 显而易见的方法"
这与真理学说的单一来源相似.不幸的是,单一显而易见的原则一直是Python的渴望,而不是真正的指导原则.考虑一下Python中非常强大的数组解析.它们在功能上等同于map
和filter
功能:
[e for e in some_array if some_condition(e)] filter(some_array, some_condition)
lambda
并且def
是一样的.
这是一个意见问题,但我会说,用于一般用途的Python语言中没有明显破坏任何东西的东西都是"Pythonic".