Ray*_*ega 95 python syntax lambda function
我主要使用lambda函数,但有时使用似乎提供相同行为的嵌套函数.
这里有一些简单的例子,如果在另一个函数中找到它们,它们在功能上做同样的事情:
Lambda函数
>>> a = lambda x : 1 + x
>>> a(5)
6
Run Code Online (Sandbox Code Playgroud)
嵌套功能
>>> def b(x): return 1 + x
>>> b(5)
6
Run Code Online (Sandbox Code Playgroud)
使用一个优于另一个是否有优势?(性能?可读性?限制?一致性?等)
它甚至重要吗?如果不这样做那就违反了Pythonic原则:
nos*_*klo 94
如果您需要将lambda名称指定给名称,请使用def替代名称.defs只是赋值的语法糖,所以结果是一样的,它们更灵活,更易读.
lambdas可以使用一次,扔掉没有名字的函数.
但是,这个用例非常罕见.您很少需要传递未命名的函数对象.
内置map()和filter()需要函数对象,但是列表推导和生成器表达式通常比那些函数更具可读性,并且可以覆盖所有用例,而不需要lambdas.
对于你真的需要一个小函数对象的情况,你应该使用operator模块函数,operator.add而不是lambda x, y: x + y
如果你仍然需要一些lambda不被覆盖的东西,你可以考虑写一个def,只是为了更具可读性.如果函数比operator模块上的函数更复杂,def则可能更好.
所以,现实世界的好用lambda例非常罕见.
Tho*_*ele 30
实际上,对我来说有两点不同:
第一个是关于他们做什么以及他们返回什么:
def是一个不返回任何内容的关键字,并在本地名称空间中创建"名称".
lambda是一个返回函数对象的关键字,不会在本地名称空间中创建"名称".
因此,如果你需要调用一个带有函数对象的函数,在一行python代码中执行该操作的唯一方法是使用lambda.没有与def相当的东西.
在某些框架中,这实际上很常见; 例如,我使用Twisted很多,所以做了类似的事情
d.addCallback(lambda result: setattr(self, _someVariable, result))
Run Code Online (Sandbox Code Playgroud)
很常见,而且对lambdas更简洁.
第二个区别是关于允许实际功能的内容.
例如,
def p(x): print x
Run Code Online (Sandbox Code Playgroud)
按预期工作,而
lambda x: print x
Run Code Online (Sandbox Code Playgroud)
是一个SyntaxError.
当然,也有变通方法-代替print用sys.stdout.write,或import用__import__.但在这种情况下,通常你最好使用一个函数.
Chr*_*lor 21
在这次采访中, 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:]
Run Code Online (Sandbox Code Playgroud)
我写了它,我花了一分钟才弄明白.这是来自项目欧拉 - 我不会说哪个问题因为我讨厌剧透,但它在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
Run Code Online (Sandbox Code Playgroud)
更可取的是:lambda 函数还是嵌套函数 (
def)?
与常规函数相比,使用 lambda 有一个优点:它们是在表达式中创建的。
有几个缺点:
'<lambda>')它们也是相同类型的对象。由于这些原因,我通常更喜欢使用def关键字而不是 lambda来创建函数。
lambda 产生与常规函数相同类型的对象
>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
...
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True
Run Code Online (Sandbox Code Playgroud)
由于 lambda 是函数,因此它们是一流的对象。
lambdas 和函数:
但是默认情况下,lambdas 缺少函数通过完整函数定义语法获得的一些东西。
__name__是'<lambda>'Lambda 毕竟是匿名函数,所以它们不知道自己的名字。
>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'
Run Code Online (Sandbox Code Playgroud)
因此,无法在其命名空间中以编程方式查找 lambda。
这限制了某些事情。例如,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
Run Code Online (Sandbox Code Playgroud)
我们可以foo很好地查找——因为它知道自己的名字:
>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>
Run Code Online (Sandbox Code Playgroud)
基本上,没有记录 lambdas。让我们重写foo以更好地记录:
def foo() -> int:
"""a nullary function, returns 0 every time"""
return 0
Run Code Online (Sandbox Code Playgroud)
现在, foo 有文档:
>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:
foo() -> int
a nullary function, returns 0 every time
Run Code Online (Sandbox Code Playgroud)
然而,我们没有相同的机制来向 lambdas 提供相同的信息:
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda (...)
Run Code Online (Sandbox Code Playgroud)
但我们可以破解它们:
>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:
<lambda> lambda ) -> in
nullary -> 0
Run Code Online (Sandbox Code Playgroud)
但是可能有一些错误弄乱了帮助的输出。
Lambda 不能返回复杂的语句,只能返回表达式。
>>> lambda: if True: 0
File "<stdin>", line 1
lambda: if True: 0
^
SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)
诚然,表达式可能相当复杂,如果你非常努力,你可能可以用 lambda 来完成同样的事情,但增加的复杂性更不利于编写清晰的代码。
为了清晰和可维护性,我们使用 Python。过度使用 lambdas 可以解决这个问题。
这是唯一可能的好处。由于您可以使用表达式创建 lambda,因此您可以在函数调用中创建它。
在函数调用中创建函数可以避免(廉价的)名称查找,而不是在其他地方创建的名称查找。
但是,由于 Python 是经过严格评估的,因此除了避免名称查找之外,这样做没有其他性能提升。
对于非常简单的表达式,我可能会选择 lambda。
在进行交互式 Python 时,我也倾向于使用 lambdas,以避免多行。当我想在调用时将参数传递给构造函数时,我使用以下类型的代码格式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
Run Code Online (Sandbox Code Playgroud)
现在:
>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304
Run Code Online (Sandbox Code Playgroud)
我相信上面的微小的时间差可以归因于在名称查找return_nullary_function-注意,这是非常微不足道的。
Lambda 非常适合非正式情况,在这种情况下,您希望尽量减少代码行数以支持创建奇异点。
Lambdas 不适合更正式的情况,在这种情况下,您需要为稍后的代码编辑器提供清晰的信息,尤其是在它们不重要的情况下。
我们知道我们应该给我们的对象起个好名字。当对象没有名称时,我们如何做到这一点?
由于所有这些原因,我通常更喜欢创建函数 withdef而不是 with lambda。
我同意nosklo的建议:如果你需要给这个函数命名,请使用def.我保留lambda函数用于我只是将一小段代码传递给另一个函数的情况,例如:
a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )
Run Code Online (Sandbox Code Playgroud)
虽然同意其他答案,但有时它更具可读性。这是一个lambda派上用场的示例,在我不断遇到 N 维的用例中defaultdict。
下面是一个例子:
from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)
Run Code Online (Sandbox Code Playgroud)
我发现它比def为第二维创建 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)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,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)
Run Code Online (Sandbox Code Playgroud)
使用预先存在的函数可以使代码在许多情况下更具可读性.
Pythonic原则:"应该有一个 - 最好只有一个 - 显而易见的方法"
这与真理学说的单一来源相似.不幸的是,单一显而易见的原则一直是Python的渴望,而不是真正的指导原则.考虑一下Python中非常强大的数组解析.它们在功能上等同于map和filter功能:
[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)
Run Code Online (Sandbox Code Playgroud)
lambda并且def是一样的.
这是一个意见问题,但我会说,用于一般用途的Python语言中没有明显破坏任何东西的东西都是"Pythonic".
| 归档时间: |
|
| 查看次数: |
58620 次 |
| 最近记录: |