【发布时间】:2014-09-20 12:31:00
【问题描述】:
每当我使用 lambda 表达式时,都会收到此 pep8 警告。不推荐使用 lambda 表达式吗?如果不是为什么?
【问题讨论】:
-
为清楚起见,该问题指的是自动签入
flake8(flake8.pycqa.org) 的消息
每当我使用 lambda 表达式时,都会收到此 pep8 警告。不推荐使用 lambda 表达式吗?如果不是为什么?
【问题讨论】:
flake8 (flake8.pycqa.org) 的消息
您遇到的PEP-8 中的建议是:
始终使用 def 语句而不是赋值语句 将 lambda 表达式直接绑定到名称。
是的:
def f(x): return 2*x没有:
f = lambda x: 2*x第一种形式表示生成的名称 函数对象是专门的 'f' 而不是通用的 '
'。 这对于回溯和字符串表示更有用 一般的。赋值语句的使用消除了唯一 lambda 表达式可以提供优于显式 def 语句的好处 (即它可以嵌入到更大的表达式中)
将 lambdas 分配给名称基本上只是复制了 def 的功能 - 通常,最好采用单一方式来避免混淆并提高清晰度。
lambda 的合法用例是你想使用一个函数而不分配它,例如:
sorted(players, key=lambda player: player.rank)
一般来说,反对这样做的主要论据是def 语句会导致更多的代码行。我对此的主要反应是:是的,这很好。除非你是打代码打高尔夫球,否则你不应该做的事情是尽量减少行数:要清楚而不是简短。
【讨论】:
def 的建议方法时,你会得到E704 multiple statements on one line (def),如果你把它分成两行,你会得到E301 expected 1 blank line, found 0 :-/
故事是这样的,我有一个简单的 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 也没有增加。此时代码检查器会抱怨该函数没有文档字符串。
在我看来,这条规则最好在有意义的时候避免和打破,使用你的判断。
【讨论】:
a = [x + offset for x in simple_list]。此处无需使用map 和lambda。
x + offset 部分移动到一个抽象位置,无需更改超过一行代码即可更新该位置。使用您提到的列表推导,您仍然需要两行包含x + offset 的代码,它们现在将位于列表推导中。为了按照作者的意愿提取这些内容,您需要 def 或 lambda。
def 和lambda,还可以使用functools.partial:f = partial(operator.add, offset),然后是a = list(map(f, simple_list))。
def f(x): return x + offset(即在一行上定义的简单函数)怎么样?至少对于 flake8,我没有收到关于空行的抱怨。
a, b = [[x + offset for x lst] for lst in (simple_list, another_simple_list)]
我还遇到了一个甚至无法使用定义(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
f 一样可访问
@staticmethod 和@classmethod 的不需要对象,只需SomeClass.also_not_reachable(尽管它们需要独特的名称)。如果您需要从类方法中访问它们,只需使用 self.also_not_reachable
*not_reachable 方法重命名为 not_as_easily_reachable_from_class_definition_as_a_lambda xD
这对我在课堂上有效,删除 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)
【讨论】: