E731不分配lambda表达式,使用def


193

每当我使用lambda表达式时,都会收到此pep8警告。不建议使用lambda表达式吗?如果不是,为什么?


4
为了清楚起见,问题是指自动检入的消息flake8flake8.pycqa.org
rakslice

Answers:


229

您遇到的PEP-8中的建议是:

始终使用def语句代替将lambda表达式直接绑定到名称的赋值语句。

是:

def f(x): return 2*x 

没有:

f = lambda x: 2*x 

第一种形式表示结果函数对象的名称专门为'f'而不是通用的'<lambda>'。通常,这对于回溯和字符串表示形式更为有用。使用赋值语句消除了lambda表达式可以提供的优于显式def语句的唯一好处(即,它可以嵌入到较大的表达式中)

为名称分配lambda基本上只是复制了def- 的功能-通常,最好以一种单一的方式进行操作以避免混淆并提高清晰度。

lambda的合法用例是您要在不分配功能的情况下使用该功能,例如:

sorted(players, key=lambda player: player.rank)

通常,反对这样做的主要理由是def语句将导致更多的代码行。我对此的主要回应是:是的,这很好。除非您是打高尔夫球的人,否则不应该减少行数:一目了然。


5
我看不出情况如何恶化。追溯仍将包括错误的行号和源文件。一个可能会说“ f”,而另一个可能会说“ lambda”。也许lambda错误更容易扫描,因为它不是单字符函数名称,也不是名称不正确的长名称?
g33kz0r 2015年

4
@ g33kz0r好吧,可以肯定的是,如果您认为其余的代码质量很差,那么遵循约定将不会给您带来太大的好处。总的来说,这不是世界末日,但这仍然不是一个好主意。
Gareth Latty

39
这个答案不是很有帮助,因为当运行建议的def通过PEP8检查器使用的方法时,您会得到E704 multiple statements on one line (def),如果将其分为两行,则会得到E301 expected 1 blank line, found 0:-/
Adam Spiers

4
我同意应该分开。我的观点是,a)在上面的答案代码中未将其拆分,导致产生E704; b)如果将其拆分,则需要在其上方加上难看的空白行,以避免E301。
亚当·斯皮尔斯

3
当我想强调纯函数(无副作用)时,我使用lambdas,有时我不得不在两个地方使用相同的函数,即groupby和sort sort。因此,我无视这一约定。
manu

119

这是一个故事,我有一个简单的lambda函数,我使用了两次。

a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)

这只是为了表示,我已经遇到了几个不同的版本。

现在,为了保持干燥状态,我开始重用此通用lambda。

f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)

在这一点上,我的代码质量检查器抱怨lambda是一个命名函数,因此我将其转换为一个函数。

def f(x):
    return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)

现在,检查者抱怨函数必须在前后插入一个空白行。

def f(x):
    return x + offset

a = map(f, simple_list)
b = map(f, another_simple_list)

在这里,我们现在有6行代码,而不是原始的2行,但没有增加可读性,也没有增加pythonic的代码。在这一点上,代码检查器抱怨该函数没有文档字符串。

在我看来,最好在合理的情况下避免并破坏该规则,请运用您的判断。


13
a = [x + offset for x in simple_list]。无需使用maplambda这里。
乔治

8
@Georgy我认为关键是将x + offset部分移动到一个抽象的位置,可以在不更改多行代码的情况下进行更新。就像您提到的列表理解一样,您仍然需要两行包含x + offset它们的代码。为了按照作者的意愿将其删除,您需要一个deflambda
朱利安

1
@Julian除deflambda一个也可以使用functools.partialf = partial(operator.add, offset)然后a = list(map(f, simple_list))
乔治

怎么样def f(x): return x + offset(即,在一行上定义的简单函数)?至少对于flake8,我没有抱怨空白行。
DocOc

1
@Julian在某些情况下,您可以使用嵌套的理解:a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
wjandrea

24

Lattyware是完全正确的:基本上,PEP-8希望您避免诸如此类的事情

f = lambda x: 2 * x

而是使用

def f(x):
    return 2 * x

但是,正如最近 bug报告(2014年8月),语句,如下面现在是否符合:

a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x

由于我的PEP-8检查器尚未正确实现此功能,因此我暂时关闭了E731。


8
即使使用def,PEP8检查器也会抱怨E301 expected 1 blank line, found 0,因此您必须在其之前添加一个难看的空白行。
亚当·斯皮尔斯

1

我还遇到了甚至无法使用def(ined)函数的情况。

class SomeClass(object):
  # pep-8 does not allow this
  f = lambda x: x + 1  # NOQA

  def not_reachable(self, x):
    return x + 1

  @staticmethod
  def also_not_reachable(x):
    return x + 1

  @classmethod
  def also_not_reachable(cls, x):
    return x + 1

  some_mapping = {
      'object1': {'name': "Object 1", 'func': f},
      'object2': {'name': "Object 2", 'func': some_other_func},
  }

在这种情况下,我真的很想做一个属于该类的映射。映射中的某些对象需要相同的功能。将命名函数放在类之外是不合逻辑的。我还没有找到从类主体内部引用方法(静态方法,类方法或普通方法)的方法。运行代码时,尚不存在SomeClass。因此,也不可能从类中引用它。


您可以also_not_reachable在映射定义中将其称为SomeClass.also_not_reachable
yaccz

1
我不知道您想在这里提出什么观点。f对于我来说,您的每个函数名称都可以像2.7和3.5 一样访问
Eric

不,除了lambda函数之外,所有函数都无法从Class主体中访问。您将得到AttributeError:如果您尝试访问some_mapping对象中的那些函数之一,则类型对象'SomeClass'没有属性'...'。
simP

3
@simP都可以轻松访问。有@staticmethod@classmethod不需要的对象,只是SomeClass.also_not_reachable(尽管它们需要独特的名称)。如果您需要从类方法访问它们,请使用self.also_not_reachable
ababak

@simP也许您应该重命名您的 *not_reachable方法为not_as_easily_reachable_from_class_definition_as_a_lambdaxD
Romain Vincent
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.