E731不指定lambda表达式,使用def

Kec*_*yal 171 python lambda pep

每当我使用lambda表达式时,我都会得到这个pep8警告.是不是建议使用lambda表达式?如果不是为什么?

Gar*_*tty 198

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

始终使用def语句而不是将lambda表达式直接绑定到名称的赋值语句.

是:

def f(x): return 2*x 
Run Code Online (Sandbox Code Playgroud)

没有:

f = lambda x: 2*x 
Run Code Online (Sandbox Code Playgroud)

第一种形式意味着生成的函数对象的名称特别是'f'而不是通用的'<lambda>'.这对于一般的回溯和字符串表示更有用.使用赋值语句消除了lambda表达式可以在显式def语句上提供的唯一好处(即它可以嵌入到更大的表达式中)

将lambdas分配给名称基本上只是复制了它的功能def- 并且通常,最好以单一方式执行某些操作以避免混淆并提高清晰度.

lambda的合法用例是你想要在不指定函数的情况下使用函数的地方,例如:

sorted(players, key=lambda player: player.rank)
Run Code Online (Sandbox Code Playgroud)

对于简单的操作,operator模块提供了一些有用的选项attrgetter,itemgettermethodcaller这往往能代替labmdas那些刚刚访问属性(S),项目(S)和调用方法.

例如,上面的内容可以这样完成operator.attrgetter:

sorted(players, key=operator.attrgetter('rank'))
Run Code Online (Sandbox Code Playgroud)

  • 这个答案不是很有用,因为当运行建议的方法通过PEP8检查器使用`def`时,你会得到`E704在一行上的多个语句(def)`,如果你将它分成两行,你会得到`E301' 1空行,找到0`: - / (32认同)
  • 我不知道它会变得更糟.回溯仍将包括错误的行号和源文件.有人可能会说"f",而另一个则说"lambda".也许lambda错误更容易扫描,因为它不是单字符函数名称,或者名称不好的长名称? (4认同)
  • @ g33kz0r嗯,当然,如果你认为你的代码的其余部分质量很差,那么下面的约定将不会给你带来太多帮助.总的来说,不,这不是世界末日,但它仍然是一个坏主意. (4认同)
  • 我同意它应该分开.我的观点是:a)它没有在上面的答案代码中分开,导致E704,和b)如果你拆分它,你需要一个丑陋的空白行以避免E301. (3认同)
  • 当我想强调纯函数(没有副作用)时我使用lambdas,有时我必须在两个地方使用相同的函数,即groupby和sort一起.所以我忽略了这个惯例. (3认同)
  • @g33kz0r Prettier 在完全属于您自己的代码库中很好(虽然很难保证这一点,事情经常会迁移),但在其他地方,最好尝试并遵循标准以帮助其他人更有效地阅读您的代码。Lambda 在 Python 中有一个非常特定的用途,以这种方式使用它只会使您的代码可读性降低,客观上更糟(正如答案所述,您在函数对象上获得了一个正确的名称,这对于调试要好得多)。 (2认同)
  • 不想引发一场口水战,但像“以这种方式使用它只会让你的代码可读性降低”之类的说法对我来说似乎非常主观。 (2认同)
  • @g33kz0r 至少,函数定义是比 lambda 更明显和常用的语言特性,使它们更容易理解。如果你真的认为它在可读性方面更好,那么它在功能和调试方面*仍然*更差。 (2认同)
  • @AdamSpiers将一个块放在同一行上通常被认为是不好的形式 - 我怀疑它在PEP中给出了类似的相似性,但你应该把它分成两行.不确定你的第二个问题是什么,但不是那个问题. (2认同)
  • 这是对 PEP-8 警告的一个很好的描述,因此它回答了问题,但我总是禁用 E731,事实上我建议其他人也这样做。使用 def 来处理短函数是相当难看的。我的任务是标准化我所参与的应用程序,以遵守 PEP-8 规则,但对于这个特定规则,团队中的每个人都认为这是一个重大的变化,变得更糟。不要相信我的话——在 10 行上编写 10 个不同的短 lambda 函数,将它们更改为 defs(一行或多行),然后自己决定。但我认为答案是明确的。 (2认同)
  • @TheGerm:我真的不明白这种想法-我一点也不觉得丑陋,使用def是一致的(具有更长的函数,并且如果函数本身后来变得很长),并且除了(函数名之外)还有其他好处进行调试)。无论如何,拥有一个标准的全部目的是提供一致性-坚持它可能对您的眼睛来说并不完美,但这将意味着每个人都可以接受它。当然,每个人都可以自由地执行他们在代码中想要的事情,但是我总是建议您遵循标准。 (2认同)
  • @GarethLatty,我通常是“坚持标准”的忠实拥护者。但是,这只是一个例子,我(和团队中的其他人)认为这直接损害了可读性。如果您想知道的话,我们的用例是可以应用于各种网格列的多个短格式功能(例如,添加百分号,先显示姓氏然后再显示名字)。 (2认同)
  • 在我看来,如果这是你**调用**的东西,请使用 `def g: ... g()`。如果它是您**作为参数传递**的东西,请使用 `f = lambda ... h(f)`。 (2认同)
  • 请注意,如果您在循环中创建这些函数,则使用“def”将覆盖循环中函数的最后一个定义,而“lambda”将每次创建一个新函数。如果您使用循环来创建函数列表,则需要使用 lambda,否则您将只有一个函数。 (2认同)
  • @BallpointBen我不太清楚您的意思,但是据我所知(并试图进行测试),那不是真的。你能举个例子吗? (2认同)
  • 有点惊讶的是,没有人提到你可能想要将 lambda 分配给变量的第一个原因 - 因为 python 的类型推断可以自动为该变量选择正确的类型,而对于“def”却不能。这意味着对于您只想分解和标记的非常简单的表达式,您不仅需要使用 2 行 def,而且您*还*必须正确键入注释,这对于推理已经可以弄清楚并可以计算出的内容来说是多余的当事物的类型发生变化时,会产生很多有趣的错误,但你不知道更新注释,天知道在哪里 (2认同)

ian*_*kit 106

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

a = map(lambda x : x + offset, simple_list)
b = map(lambda x : x + offset, another_simple_list)
Run Code Online (Sandbox Code Playgroud)

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

现在,为了保持干燥,我开始重用这个常见的lambda.

f = lambda x : x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Run Code Online (Sandbox Code Playgroud)

此时我的代码质量检查器抱怨lambda是一个命名函数,所以我把它转换成一个函数.

def f(x):
    return x + offset
a = map(f, simple_list)
b = map(f, another_simple_list)
Run Code Online (Sandbox Code Playgroud)

现在检查器抱怨函数必须由前后一个空行限定.

def f(x):
    return x + offset

a = map(f, simple_list)
b = map(f, another_simple_list)
Run Code Online (Sandbox Code Playgroud)

在这里,我们现在有6行代码而不是原始的2行,没有增加可读性,也没有增加pythonic.此时,代码检查器会抱怨没有docstrings的函数.

在我看来,这个规则可以更好地避免和破坏,当它有意义时,运用你的判断.

  • `a = [x + simple_list中x的偏移量]`.这里不需要使用`map`和`lambda`. (12认同)
  • @Georgy我相信关键是将x + offset部分移到一个抽象的位置,可以在不更改多行代码的情况下进行更新。就像您提到的列表推导一样,您仍然需要两行包含x + offset的代码,它们现在才在列表推导中。为了按照作者的意愿将其删除,您需要使用`def`或`lambda`。 (5认同)

Elm*_*ise 23

Lattyware是绝对正确的:基本上PEP-8希望你避免像这样的事情

f = lambda x: 2 * x
Run Code Online (Sandbox Code Playgroud)

而是使用

def f(x):
    return 2 * x
Run Code Online (Sandbox Code Playgroud)

但是,正如最近的bug报告(2014年8月)中所述,现在符合以下语句:

a.f = lambda x: 2 * x
a["f"] = lambda x: 2 * x
Run Code Online (Sandbox Code Playgroud)

由于我的PEP-8检查器尚未正确实现,我暂时关闭了E731.

  • 即使使用`def`,PEP8检查器也会抱怨`E301预计有1个空行,找到0`,所以你必须在它之前添加一个丑陋的空白行. (8认同)