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

2025-03-05 09:15:00
admin
原创
41
摘要:问题描述:每当我使用 lambda 表达式时,我都会收到此 pep8 警告。不推荐使用 lambda 表达式吗?如果不推荐,为什么?解决方案 1:您遇到的PEP-8中的建议是:始终使用 def 语句,而不是将 lambda 表达式直接绑定到名称的赋值语句。是的:def f(x): return 2*x 不:...

问题描述:

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


解决方案 1:

您遇到的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语句会导致代码行数增加。我对此的主要回应是:是的,这很好。除非您正在进行代码打磨,否则尽量减少代码行数并不是您应该做的事情:追求清晰而不是简短。

解决方案 2:

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

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

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

现在,为了让事情保持 DRY,我开始重用这个常见的 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 风格也没有提高。此时,代码检查器会抱怨该函数没有文档字符串。

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

解决方案 3:

Lattyware 完全正确:基本上PEP-8希望你避免以下事情

f = lambda x: 2 * x

而是使用

def f(x):
    return 2 * x

然而,正如最近的错误报告(2014 年 8 月)中所述,如下声明现在是合规的:

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

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

解决方案 4:

我还遇到过甚至无法使用定义函数的情况。

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 还不存在。因此从类中引用它也是不可能的。

解决方案 5:

主要原因似乎是使用 lambda 表达式创建新函数会降低代码的可读性,而使用 def 关键字创建这些函数则不行。如果您有一些代码,并且一些函数是用 def 创建的,而另一些函数是用 lambda 创建的,那么区分哪些是函数、哪些是变量可能会令人困惑。

简而言之,def 关键字用于创建新函数,而 lambda 用于匿名函数(即不与名称绑定的函数)。将变量定义为某个 lambda 表达式的结果似乎与 lambda 表达式的预期用例背道而驰。

解决方案 6:

如果您正在使用 mypy,那么选择 defs 的另一个原因是类型安全。

尽管以下代码包含类型错误,但它仍将通过 mypy 类型检查:

y = lambda x: x**2
print(y("fred"))

我们可以使用下面带注释的代码使其类型安全,现在 mypy 将按预期检测到错误。

from typing import Callable

y: Callable[[int], int] = lambda x: x**2
print(y("fred"))

但是,这看起来有点笨拙。让我们与下面的类型安全def替代方案进行比较。

def y(x: int) -> int:
   return x**2


print(y("fred"))

可以说,该def版本更易读、更简洁(客观地说,虽然它占用了两行,但总体字符数更少,并且不需要额外导入)。

解决方案 7:

我最近遇到了一个非常合理的理由来直接分配lambda表达式(一如既往,可以通过创建额外的代码来避免)。基本上,我需要在以后读取变量的值,但我还需要从中构造一些我使用的接口期望延迟评估的东西。

#my_module.py
from ... import get_global_config, Other

class Some(Other):

    SOME_MAPPING = { ... }

    def __init__(self, ...):
        some_attr = lambda: SOME_MAPPING[
            get_global_config().some_param
        ]

        ...
        super().__init__(self, some_attr, ...)

当我构造对象时,global_config所讨论的对象可能会或可能不会被设置/构造/完全配置,所以我需要将获取配置的值推迟到实际需要的时候。

在正常情况下,可以通过使用属性来避免这种情况,但是我正在使用/继承的接口要求我Callable[[], ...]为特定属性分配一些具体的东西或类型的闭包,而我目前真的不想重构数千行代码。

解决方案 8:

这对我来说在一个类中起作用,删除 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)
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1887  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1425  
  在制造业数字化转型的进程中,PLM(产品生命周期管理)系统、ERP(企业资源计划)系统、MES(制造执行系统)以及 CAD(计算机辅助设计)软件都扮演着至关重要的角色。然而,这些系统和软件各自独立运行时,往往难以发挥出最大的协同效应。实现 PLM 系统与 ERP、MES、CAD 的有效集成,成为提升企业整体竞争力、优化...
plm系统的主要功能模块   3  
  产品生命周期管理(PLM)作为一种先进的管理理念和技术,在电子与半导体行业正发挥着日益重要的作用。随着电子与半导体行业的快速发展,产品更新换代速度加快,市场竞争愈发激烈,企业面临着诸多挑战,如缩短产品上市时间、提高产品质量、降低成本等。而PLM的应用为企业应对这些挑战提供了有效的解决方案,展现出巨大的应用价值。提升产品...
plm项目   4  
  PLM(产品生命周期管理)项目管理软件在现代企业的产品研发、生产与运营中扮演着至关重要的角色。它整合了从产品概念设计到退役的全流程数据与流程,助力企业提升效率、降低成本并增强创新能力。随着科技的飞速发展以及企业需求的不断演变,未来十年 PLM 项目管理软件的发展充满了无限可能,值得深入探讨与预测。智能化与自动化趋势智能...
plm产品全生命周期管理   6  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用