【问题标题】:Most pythonic way to port this tuple unpacking with lambda from Python 2 into Python 3使用 lambda 将这个元组解包从 Python 2 移植到 Python 3 的最 Pythonic 方式
【发布时间】:2017-04-08 14:22:20
【问题描述】:

我有以下 Python 2 代码,它在 lambda 中解包一个元组。此 lambda 包含在 for 循环中。

    for lab, lab_pred, length in zip(labels, labels_pred, sequence_lengths):
        accs += map(lambda (a, b): a == b, zip(lab, lab_pred))

将其移植到 Python 3 的最佳方法是什么?

【问题讨论】:

  • 除了 Python 3 函数 args 中缺少元组解包之外,还有另一个问题:Python 3 中的 map 返回的是迭代器而不是列表。 Python 2 中许多返回列表的函数就是这种情况。
  • 这只是 Python 核心开发人员教学方法的另一个案例——打破事物以“教他们”变得更加“pythonic”(并使 Py2/Py3 互操作更加困难)。请参阅我的答案以了解更一般的情况,而不仅仅是您的特定 sn-p。

标签: python lambda


【解决方案1】:

我认为最好的解决方案是不使用 maplambda,而是使用列表推导:

accs += [a == b for a, b in zip(lab, lab_pred)]

【讨论】:

  • 绝对!将 lambda 与 mapfilter 一起使用有点愚蠢,因为这意味着您在每个项目上调用一个函数只是为了执行 lambda 中的表达式,而使用列表 comp(或 gen exp)执行表达式直接地。 Python 函数调用比 C 函数调用的开销要大得多,因此在不需要它们时最好避免它们。
【解决方案2】:

如果您更喜欢功能性风格,则有:

from operator import eq
from itertools import starmap

accs.extend(starmap(eq, zip(lab, lab_pred)))

【讨论】:

    【解决方案3】:

    这是 Python3 中的故意回归(虽然我不知道原因 - 如果你碰巧 - 请在下面评论)以阻止 lambda 并从长远来看 - 完全使用 Python2。

    Pythonic 快速修复

    (已编辑,之前的想法并没有真正奏效) 也可以在这里查看:https://stackoverflow.com/a/47947955/1338797

    如果你的 lambda 是平的,有升级到 Python3 的路径:

    lambda (x, y): x + y
    

    变成

    lambda xy: (lambda x, y: x + y)(*xy)
    

    不错,但有两个缺点:

    1. 欢迎使用 Lisp ;) 它很复杂(但是像 str.join 这样的 Python 语言)

    2. 它不会剪切嵌套元组,例如:lambda ((x0, y0), (x1, y1)): abs(x1-x0) + abs(y1-y0)

    3. 一个额外的 lambda。

    为什么他们强迫我们使用小的 def 函数?

    Lambda 不好有几个原因(大约 3-4 可能是有效的):

    1. 只是因为:lambda 在 Python 中被破坏了。知道这一点是“pythonic”。

    2. Lambdas(在 Python 中,而不是在其他语言中!我不会在以下几点重复此免责声明)只能处理单个表达式。

    3. Lambda 没有 __name__s。

    4. Lambda 有丑陋的 __repr__esentations。

    5. Lambdas 可以使代码变慢。 (经常不必要地创建时)

    6. Lambda 很慢。 (运行,与竞争结构相比)

    (无论如何,5 和 6 仅在大多数性能关键代码中相关)。

    建议使用Python中的小函数,他们认为没问题,因为它只需要多出2行。 (2 而不是 0,因为 lambda 可以是内联的)。因此lambda x, y: x == y 变为:

    def are_equal(x, y):
        return x == y
    

    (在这里忘记operator.eq,不是每个 lambda 在这个模块中都有它的等价物)。

    实际上,如果你坚持使用 PEP-8,这个函数在本地范围内需要额外的 4 行,在全局范围内需要额外的 6 行,包括空行填充。

    示例情况:如何保持兼容性

    假设您有一个列表或其他可迭代的元组。您想使用max(..., key=...) 获得最大值。之后,您可以直接解包元组。在 Python2 时代,它会是:

    x, y, w, h = max(faces, key=lambda (x, y, w, h): w * h)
    

    (同样,你可以在这里告诉我 typing.Namedtuples、dataclasses@attr.s 的优越性,但现在我从 OpenCV 得到 listtuples。

    我发现使用函数最不痛苦的方式:

    def face_area(*args):
        x, y, w, h = args if len(args) == 4 else args[0]
        return w * h
    
     x, y, w, h = max(faces, key=face_area)
    

    Python2 将在args 中获得一个嵌套元组,Python3 将获得一个长度为 4 的元组。您可以像上面那样手动解包,然后继续 return 处理您的结果。

    有人会说,它让代码有机会变得更加自我记录,因为我不得不为key 函数想一个名字。

    【讨论】:

    • 仅供参考 - 请参阅基本原理:python.org/dev/peps/pep-3113 - 总结一下:“我们将删除它,因为它很方便而且没有人知道使用它。”
    猜你喜欢
    • 1970-01-01
    • 2017-06-18
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多