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

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

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

I get this pep8 warning whenever I use lambda expressions. Are lambda expressions not recommended? If not why?


回答 0

您遇到的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语句将导致更多的代码行。我对此的主要回应是:是的,这很好。除非您是打高尔夫球的人,否则不应该减少行数:一目了然。

The recommendation in PEP-8 you are running into is:

Always use a def statement instead of an assignment statement that binds a lambda expression directly to a name.

Yes:

def f(x): return 2*x 

No:

f = lambda x: 2*x 

The first form means that the name of the resulting function object is specifically ‘f’ instead of the generic ‘<lambda>’. This is more useful for tracebacks and string representations in general. The use of the assignment statement eliminates the sole benefit a lambda expression can offer over an explicit def statement (i.e. that it can be embedded inside a larger expression)

Assigning lambdas to names basically just duplicates the functionality of def – and in general, it’s best to do something a single way to avoid confusion and increase clarity.

The legitimate use case for lambda is where you want to use a function without assigning it, e.g:

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

In general, the main argument against doing this is that def statements will result in more lines of code. My main response to that would be: yes, and that is fine. Unless you are code golfing, minimising the number of lines isn’t something you should be doing: go for clear over short.


回答 1

这是一个故事,我有一个简单的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的代码。在这一点上,代码检查器抱怨该函数没有文档字符串。

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

Here is the story, I had a simple lambda function which I was using twice.

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

This is just for the representation, I have faced couple of different versions of this.

Now, to keep things DRY, I start to reuse this common lambda.

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

At this point my code quality checker complains about lambda being a named function so I convert it into a function.

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

Now the checker complains that a function has to be bounded by one blank line before and after.

def f(x):
    return x + offset

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

Here we have now 6 lines of code instead of original 2 lines with no increase in readability and no increase in being pythonic. At this point the code checker complains about the function not having docstrings.

In my opinion this rule better be avoided and broken when it makes sense, use your judgement.


回答 2

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。

Lattyware is absolutely right: Basically PEP-8 wants you to avoid things like

f = lambda x: 2 * x

and instead use

def f(x):
    return 2 * x

However, as addressed in a recent bugreport (Aug 2014), statements such as the following are now compliant:

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

Since my PEP-8 checker doesn’t implement this correctly yet, I turned off E731 for the time being.


回答 3

我还遇到了甚至无法使用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。因此,也不可能从类中引用它。

I also encountered a situation in which it was even impossible to use a def(ined) function.

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},
  }

In this case, I really wanted to make a mapping which belonged to the class. Some objects in the mapping needed the same function. It would be illogical to put the a named function outside of the class. I have not found a way to refer to a method (staticmethod, classmethod or normal) from inside the class body. SomeClass does not exist yet when the code is run. So referring to it from the class isn’t possible either.