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


你在PEP-8中遇到的建议是:

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)

将lambdas分配给名称基本上只是重复了def的功能——通常情况下,最好使用单一的方法来避免混淆并增加清晰度。

lambda的合法用例是你想使用一个函数而不给它赋值,例如:

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

一般来说,反对这样做的主要理由是def语句将导致更多代码行。我对此的主要回答是:是的,这很好。除非你在打代码高尔夫,否则尽量减少行数不是你应该做的事情:追求清晰而不是简短。


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

f = lambda x: 2 * x

而是使用

def f(x):
    return 2 * x

然而,正如在最近的bugreport(2014年8月)中所述,以下语句现在是合规的:

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

由于我的PEP-8检查器还没有正确地实现这一点,我暂时关闭了E731。


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

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行,可读性没有增加,python化也没有增加。此时,代码检查器抱怨函数没有文档字符串。

在我看来,最好避免这个规则,当它有意义时,使用你的判断。


我还遇到过一种情况,在这种情况下,甚至不可能使用已定义的函数。

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

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


这适用于我在一个类,删除lambda表达式和使用def代替,改变这个…

    def set_every(self, every: int = 1, time_unit: int = TimeUnit.Day):
        every_func = lambda x: "*" if x == 1 else "*/" + str(x)
        if TimeUnit.has_value(time_unit):
            self.month_of_year = "*"
            self.day_of_month = "*" if time_unit != TimeUnit.Day else every_func(every)
            self.day_of_week = "*" if time_unit != TimeUnit.Week else every_func(every)

由这个……

    def set_every(self, every: int = 1, time_unit: int = TimeUnit.Day):
        def every_func(x: int) -> str: return "*" if x == 1 else "*/" + str(x)
        if TimeUnit.has_value(time_unit):
            self.month_of_year = "*"
            self.day_of_month = "*" if time_unit != TimeUnit.Day else every_func(every)
            self.day_of_week = "*" if time_unit != TimeUnit.Week else every_func(every)