代码之家  ›  专栏  ›  技术社区  ›  BruceWayne

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

  •  5
  • BruceWayne  · 技术社区  · 8 年前

    我有一个lambda函数,我想对它进行添加,使其更加健壮。但是,我也希望遵循PEP8,并将我的行保持在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改成一个函数,但是我正在努力解决这个问题。我刚接触过兰姆达斯,这一点完全是从另一个问题得到的……所以是的,同意lambda是根本问题。

    2 回复  |  直到 8 年前
        1
  •  7
  •   abarnert    8 年前

    作为一般规则,我认为最好依靠自动化工具重新格式化代码,而不是像自己的计算机那样设法应用所有这些规则。

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

    • black :在语法级别重新格式化;除了最大行长度之外,根本没有配置。
    • yapf :在语法级别重新格式化;高度可配置。
    • autopep8 (和前人一样 pep8ify ):仅在表面重新格式化;不会更改已符合PEP 8的任何内容。如果您希望尽可能少的更改(例如,因为您正在重新格式化长期存在的代码,不希望在源代码管理中有大量的更改列表),则非常有用。

    这里是什么 黑色 使用您的代码:

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

    这占据了大量的垂直空白。但是你不能配置 黑色 以不同的方式对待它。那么,你能做什么?

    无论何时 黑色 坚持将我的代码重新格式化为对我来说不好的代码,这意味着我必须将代码重新组织为更容易格式化的代码。

    最明显的是把那个巨人 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改成一个函数,但是我正在努力解决这个问题。我刚接触过兰姆达斯,这一点完全是从另一个问题得到的……所以是的,同意lambda是根本问题。

    兰姆达 一个函数,就像 DEF 是。唯一的区别是:

    • DEF 是一个语句,因此不能将它放在表达式的中间。
    • 兰姆达 是表达式,因此不能在其中包含任何语句。
    • DEF 为函数命名。

    除此之外,它们编译的函数工作方式完全相同。例如:

    func = lambda x: expr(x)
    
    def func(x): return expr(x)
    

    用相同的字节码定义两个函数,除了 func.__name__ 'func' 对于 DEF 但有点像 '<lambda>' 对于 兰姆达 .

    更重要的是,如果您想向函数中抛出循环或测试, 兰姆达 你必须把它转换成一种理解或者一种if表达;用 DEF 如果合适的话,可以这样做,否则可以使用复合语句。

    但是,另一方面,如果函数没有好的名称,而且除了用作回调函数之外,它确实不值得考虑, 兰姆达 更好。例如,如果您定义的函数 return x - 3 只会用一次, DEF 真傻。

        2
  •  1
  •   Gabriel    8 年前

    首先:你的代码在做什么?

    让我们仔细阅读:

    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 有1000000个元素,您将评估999999个无用元素 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)
    

    这不是更好吗?

    (请给函数取一个更好的名称)