如何将 lambda 函数分解为自己的函数? (Lambda 目前超过 125 个字符)

Posted

技术标签:

【中文标题】如何将 lambda 函数分解为自己的函数? (Lambda 目前超过 125 个字符)【英文标题】:How to break up lambda function in to its own function? (Lambda is currently 125+ characters) 【发布时间】:2019-01-02 14:23:21 【问题描述】:

我有一个 lambda 函数,我想添加它并使其更加健壮。但是,我也想遵循 PEP 8 并将我的行保持在 79 个字符以下,正确缩进等,但在考虑如何拆分行时遇到了麻烦。

该行当前是:

styled_df = df.style.apply(lambda x: ["background: rgba(255,0,0,.3)" if('BBC' in x['newsSource'] or 'Wall' in x['newsSource']) and idx==0 else "" for idx, v in enumerate(x)], axis = 1)

到目前为止,我可以做到这一点:

styled_df = df.style.apply(
    lambda x: ["background: rgba(255,0,0,.3)" 
        if('BBC' in x['newsSource'] or 'Wall' in x['newsSource']) and
        idx == 0 else ""
        for idx, v in enumerate(x)], axis=1)

但第三行 (if('BBC' in ...) 与 PEP 8 (E128) 冲突。另外,诚然,这不是我分解它的最清晰的代码。

另外,我正计划为此添加更多条件,并且想知道这样做的最佳方法是什么。只是继续添加,并尽我所能打破线路?或者是否有针对此类问题的“最佳实践”?

编辑:正如我所想,但忘了提及,我可能可以将此 lambda 更改为一个函数,但我正在努力解决如何。我是 lambdas 新手,完全从另一个问题中得到了这个......所以是的,同意 Lambda 是根本问题。

【问题讨论】:

您有一个 150 个字符长的 lambda 并且担心 pep8?使代码可读的第 1 步是将 lambda 转换为真正的函数。 我不会关心 PEP8,而是更关心那个 lambda。 您的编辑器肯定支持其中之一:***.com/questions/1428872/… @AndrejKesely - 我正在使用 Anaconda 和 SublimeText3,它指出了这些。 @Aran-Fey - 哈哈,是的......我知道。如前所述,我可能可以减少那个 lambda,但是(正如我在 OP 中编辑的那样),我是 lambdas 的新手,我正试图弄清楚如何将它变成 Pandas 的 .apply() 可以读取的函数 【参考方案1】:

作为一般规则,我认为最好依靠自动化工具来重新格式化您的代码,而不是自己尝试弄清楚如何像计算机一样应用所有这些规则。

我知道的三个主要选择是:

black:在语法级别重新格式化;除了最大行长之外,根本没有任何配置。 yapf:在语法级别重新格式化;高度可配置。 autopep8(以及像pep8ify这样的前辈):仅在表面级别重新格式化;不会更改已经符合 PEP 8 的任何内容。如果您希望尽可能少地进行更改(例如,因为您要重新格式化长期存在的代码并且不希望在源代码管理中出现大量更改列表),这很有用。

black 对您的代码执行以下操作:

styled_df = df.style.apply(
    lambda x: [
        "background: rgba(255,0,0,.3)"
        if ("BBC" in x["newsSource"] or "Wall" in x["newsSource"]) and idx == 0
        else ""
        for idx, v in enumerate(x)
    ],
    axis=1,
)

这占用了大量的垂直空白。但是你不能配置black 来区别对待它。那么,你能做什么呢?

每当black 坚持将我的代码重新格式化为对我来说不好看的东西时,这意味着我必须将我的代码重新组织成更易于格式化的东西。

这里要做的显而易见的事情是将那个巨大的lambda 变成一个def,或者甚至两个:

def highlight(x):
    return "BBC" in x["newsSource"] or "Wall" in x["newsSource"]

def style(x):
    return [
        "background: rgba(255,0,0,.3)" if highlight(x) and idx==0 else ""
        for idx, v in enumerate(x)
    ]

styled_df = df.style.apply(style, axis=1)

已经这样做了……你甚至没有使用v;您所做的只是为第一个 (and idx == 0) 设置样式,并且仅当新闻来源包括 BBC 或 Wall 时。

因此,对于 BBC 和 Wall 的事情,您将返回一个 background 加上 len(x)-1 空字符串;对于其他事情,您只是返回 len(x) 空字符串。

假设这是你想要的逻辑,让我们明确一点:

def style(x):
    if "BBC" in x["newsSource"] or "Wall" in x["newsSource"]:
        first = "background: rgba(255,0,0,.3)"
        return [first] + [""]*(len(x)-1)
    return [""]*len(x)

styled_df = df.style.apply(style, axis=1)

您可能更喜欢["" for _ in range(x)] 而不是[""]*len(x);我不确定这里哪个更易读。


我可能可以将此 lambda 更改为一个函数,但我正在为如何做而苦苦挣扎。我是 lambdas 新手,完全从另一个问题中得到了这个......所以是的,同意 Lambda 是根本问题。

lambda 一个函数,就像 def 一样。唯一的区别是:

def 是一个语句,所以不能放在表达式的中间。 lambda 是一个表达式,因此您不能在其中包含任何语句。 def 为函数命名。

除此之外,它们编译的功能完全相同。例如:

func = lambda x: expr(x)

def func(x): return expr(x)

... 定义了两个具有相同字节码的函数,几乎所有其他函数都相同,除了deffunc.__name__'func',而lambda'<lambda>' 类似。

更重要的是,如果你想在函数中抛出循环或测试,使用lambda,你必须将其扭曲为理解或 if 表达式;使用def,您可以在合适的情况下这样做,或者在不合适的情况下使用复合语句。

但是,另一方面,如果该函数没有好的名称,并且除了用作回调函数之外确实不值得考虑,lambda 更好。例如,如果您只为 return x - 3 定义一个只会使用一次的函数,那么 def 将是愚蠢的。

【讨论】:

最后一个函数有效!谢谢!我试图将其分解,但不太明白* len(x) 的目的是什么?或者为什么需要将 "" 附加到 [first] ?编辑:非常感谢lambda 的出色解释:D @BruceWayne 你的代码返回"",除非<something> and idx==0,所以要么有len(x) 空字符串,要么有一个非空字符串和len(x)-1 空字符串。我重写了它以使这一事实更加明显,但即使在重写之后使用理解也可能更具可读性。查看编辑并告诉我您的想法。【参考方案2】:

第一件事:你的代码在做什么?

让我们仔细阅读:

lambda x: ["background: rgba(255,0,0,.3)" 
        if('BBC' in x['newsSource'] or 'Wall' in x['newsSource']) and
        idx == 0 else ""
        for idx, v in enumerate(x)]

您只对x 的第一个元素感兴趣,因为您对idx == 0 感兴趣。请记住,索引仅在第一次迭代中为零。因此,如果 x 有一个 1,000,000 个元素,您将评估 999,999 个无用的 if 条件。

据我所知,你的算法的解释是:

创建一个相同长度的x 列表,其中每个元素都是一个空字符串。如果BBC'Wall' 出现在x['newsSource'] 中,则使这个新列表的第一个元素成为字符串background: rgba(255,0,0,.3)。返回这个新列表。

这很容易编码:

def mysterious_function(x):
    new_list = [''] * len(x)

    if 'BBC' in x['newsSource'] or 'Wall' in x['newsSource']:
        new_list[0] = 'background: rgba(255,0,0,.3)'

    return new_list

您现在可以在当前代码中使用神秘功能:

styled_df = df.style.apply(mysterious_function, axis=1)

这样不是更好吗?

(请给函数起一个更好的名字)

【讨论】:

以上是关于如何将 lambda 函数分解为自己的函数? (Lambda 目前超过 125 个字符)的主要内容,如果未能解决你的问题,请参考以下文章

您如何将 lambda 函数读取为字符串?

如何将错误处理方法转换为 Lambda 函数

如何使用 C++ lambda 将成员函数指针转换为普通函数指针以用作回调

python 函数中的递归lambda map reduce 等详解

匿名函数lambda

如何将此lamda函数重写为常规函数