有人可以解释BDFL选择使Python Lambdas单行的具体原因吗?
这很好:
lambda x: x**x
这会导致错误:
lambda x:
x**x
我了解到,使lambda多行处理会以某种方式“干扰”正常的缩进规则,并且需要添加更多的例外,但这不值得吗?
以JavaScript为例。没有这些匿名功能,怎能生存?它们是必不可少的。难道Pythonista使用者不希望为了将每个多行函数都作为参数传递而不得不命名吗?
def吗?现在,它具有完全相同的视觉结构。
有人可以解释BDFL选择使Python Lambdas单行的具体原因吗?
这很好:
lambda x: x**x
这会导致错误:
lambda x:
x**x
我了解到,使lambda多行处理会以某种方式“干扰”正常的缩进规则,并且需要添加更多的例外,但这不值得吗?
以JavaScript为例。没有这些匿名功能,怎能生存?它们是必不可少的。难道Pythonista使用者不希望为了将每个多行函数都作为参数传递而不得不命名吗?
def吗?现在,它具有完全相同的视觉结构。
Answers:
吉多·范·范·罗苏姆(Guido van van Rossum)自己回答:
但是,此类解决方案通常缺少“ Pythonicity”(Python的良好功能),即良好的Python功能难以捉摸的特征。很难将Pythonic表示为硬约束。甚至Python的Zen也不能转化为对Pythonicity的简单测试...
在上面的示例中,很容易找到所提出的解决方案的致命弱点:双冒号虽然在语法上确实是明确的(“难题约束”之一),但完全是任意的,并且与Python中的任何其他事物都不相似...
但是我也拒绝这样做,因为最后(这是我无意间误导提交者的地方),我发现任何无法接受的解决方案都将基于缩进的块嵌入表达式的中间。由于我发现语句分组的替代语法(例如花括号或begin / end关键字)同样不可接受,因此,这几乎使多行lambda成为无法解决的难题。
http://www.artima.com/weblogs/viewpost.jsp?thread=147358
他说,基本上,尽管有解决方案是可行的,但与Python的方式并不一致。
在python中执行多行lambda是完全可以的:请参阅
>>> f = lambda x: (
... x**x)
>>> f
<function <lambda> at 0x7f95d8f85488>
>>> f(3)
27
真正的lambda限制是lambda必须是单个表达式的事实;它不能包含关键字(例如python2 print或return)。
GvR选择这样做是为了限制lambda的大小,因为它们通常用作参数。如果您想使用真正的功能,请使用def
def。想一想:您真的需要将callable作为函数的参数吗?并且不允许该函数的用户传递您的默认可调用对象?如果您不给他们,他们怎么能通过它?
我知道这已经很老了,但在这里作为参考。
使用lambda的替代方法可以是使用def非常规方式。目标是将a传递def给函数,该函数只能在一种情况下完成-装饰器。请注意,使用此实现def result不会创建函数,而是会创建结果reduce(),最终结果是dict。
>>> xs = [('a', 1), ('b', 2), ('a', 3), ('b', 4)]
>>> foldl = lambda xs, initial: lambda f: reduce(f, xs, initial)
>>> @foldl(xs, {})
... def result(acc, (k, v)):
... acc.setdefault(k, 0)
... acc[k] += v
... return acc
...
>>> result
{'a': 4, 'b': 6}
请注意,多语句lambda 可以完成,但只能使用非常丑陋的代码。但是,有趣的是作用域如何与此实现一起工作(请注意name变量的多次使用和变量的阴影message。
>>> from __future__ import print_function
>>> bind = lambda x, f=(lambda x: x): f(x)
>>> main = lambda: bind(
... print('Enter your name.'), lambda _: bind(
... raw_input('> '), lambda name: bind(
... 'Hello {}!'.format(name), lambda message: bind(
... print(message), lambda _: bind(
... 'Bye {}!'.format(name), lambda message: bind(
... print(message)
... ))))))
>>> main()
Enter your name.
> foo
Hello foo!
Bye foo!
一起编写多语句lambda并不像pyrospade所表明的那样糟糕:确保我们可以使用bind组成一堆monadic 函数,就像在Haskell中一样,但是由于我们处在Python的不纯净世界中,所以我们也可以使用副作用来实现相同的目的。
我在博客上介绍了几种方法。
例如,Python保证按顺序评估元组的元素,因此我们可以,像命令式一样使用;。我们可以将许多语句(如)替换print为表达式(如)sys.stdout.write。
因此,以下内容是等效的:
def print_in_tag_def(tag, text):
print "<" + tag + ">"
print text
print "</" + tag + ">"
import sys
print_ = sys.stdout.write
print_in_tag_lambda = lambda tag, text: (print_("<" + tag + ">"),
print_(text),
print_("</" + tag + ">"),
None)[-1]
请注意,我None在末尾添加了a ,并使用提取了它[-1]。这将显式设置返回值。我们不必这样做,但是如果没有它,我们将得到一个时髦的(None, None, None)返回值,我们可能会或可能不会在乎。
因此,我们可以对IO操作进行排序。局部变量呢?
Python的=形式是一条语句,因此我们需要找到一个等效的表达式。一种方法是更改作为参数传入的数据结构的内容。例如:
def stateful_def():
foo = 10
bar = foo * foo
foo = 2
return foo + bar
stateful_lambda = (lambda state: lambda *_: (state.setdefault('foo', 10),
state.setdefault('bar', state.get('foo') * state.get('foo')),
state.pop('foo'),
state.setdefault('foo', 2),
state.get('foo') + state.get('bar'))[-1])({})
在中使用了一些技巧stateful_lambda:
*_参数允许我们的lambda接受任意数量的参数。由于这允许零参数,因此我们恢复的调用约定stateful_def。
_只是一个约定,上面写着“我不会使用此变量”lambda state: lambda *_: ...
(lambda state: ...)({})
state值{}(例如state = {})state视为变量名和绑定值
state.setdefault(a, b)代替a = b和state.get(a)代替a[-1]用来提取最后一个值,就像return声明一样当然这很麻烦,但是我们可以使用辅助函数来制作更好的API:
# Keeps arguments and values close together for immediately-called functions
callWith = lambda x, f: f(x)
# Returns the `get` and `setdefault` methods of a new dictionary
mkEnv = lambda *_: callWith({},
lambda d: (d.get,
lambda k, v: (d.pop(k), d.setdefault(k, v))))
# A helper for providing a function with a fresh `get` and `setdefault`
inEnv = lambda f: callWith(mkEnv(), f)
# Delays the execution of a function
delay = lambda f x: lambda *_: f(x)
# Uses `get` and `set`(default) to mutate values
stateful_lambda = delay(inEnv, lambda get, set: (set('foo', 10),
set('bar', get('foo') * get('foo')),
set('foo', 2),
get('foo') + get('bar'))[-1])
我虽然可以提供帮助,但请使用断行器:
x = lambda x,y: x-y if x<y \
else y-x if y<x \
else 0
不要忘记python能够编写oneliners的好处,例如:
a=b=0; c=b+a; d = a+b**2 #etc etc
而且lambda非常强大,但是它并不意味着要替换1个完整函数,我的意思是您可以像hack一样(从上面的同事那里借用示例):
makeTag = lambda tagName: "<{}>".format(tagName)
closeTag = lambda tagName: makeTag("/"+str(tagName))
openTag = lambda tagName: makeTag(tagName)
writeHMTLline = lambda tag,content: ""+opetTag(tag)+str(content)+closeTag(tag)
但是,您真的要这样吗?一段时间后,它几乎是不可读的,就像从未解开的末端开始到绳索的开头。

Lambda被视为唯一的函数,在面向函数的编程中(除其他功能外)在map,filter和reduce函数中。例如,获取整数值且可被2整除的字符值
chrDev2 = lambda INT: chr(INT) if isinstance(INT,int) and INT%2==0 else INT
someStringList = map( chrDev2, range(30) )
>>> ['\x00', 1, '\x02', 3, '\x04', 5, '\x06', 7, '\x08', 9, '\n', 11, '\x0c', 13, '\x0e', 15, '\x10', 17, '\x12', 19, '\x14', 21, '\x16', 23, '\x18', 25, '\x1a', 27, '\x1c', 29]
您可以通过定义复杂函数(或更多和几个lambda,并将其放在另一个lambda中)来将其用作函数expresions函数:
def someAnon(*args): return sum(list(args))
defAnon = lambda list: [ x*someAnon(*list) for x in list]
但是Python以另一种方式提供了对函数表示的支持:-让我们说您调用了某个函数,superAwesomeFunction并且该函数可以执行一些非常出色的工作,您可以不调用它就将其分配给变量,如下所示:
SAF = superAwesomeFunction # there is no () at the end,
因此,现在当您调用SAF时,将调用superAwesomeFunction或方法。如果您在Lib文件夹中搜索,您会发现大多数python __builtin__模块都是以这种方式编写的。这样做是因为有时您需要某些功能来执行特定任务,而这些功能对于用户来说并不是必需的,但是对于多个功能来说是必需的。因此,您可以选择不使用名称为“ superAwesomeFunction”的2个函数,可以使用“ superAwesomeFunctionDoingBasicStuf”和“ realSuperAwesomeFunction”,而不是仅将“ realSuperAwesomeFunction”放入“ superAwesomeFunction”变量中就可以了。
您可以通过在console中输入importedModule.__file__(实际示例import os;os.__file__)来找到导入模块的位置,只需跟随该目录访问名为importedModule.py的文件,然后在编辑器中将其打开,即可找到如何最大化自己的“知识”。
希望这对您和其他遇到麻烦的同事有所帮助。