【问题标题】:Capturing method in if statement in a list comprehension列表理解中 if 语句中的捕获方法
【发布时间】:2017-08-27 23:28:12
【问题描述】:

我有以下用例:

[(x, f(x)) for x in list_x if f(x) == cond(x)]

在列表理解之上,我认为 f(x) 调用了两次?如何避免这种情况并捕获 f(x) 的值,以便仅调用一次 f(x)。

我想,简单的解决方法是将上面的列表推导转换为 for 循环,但我很好奇是否可以使用列表推导有效地完成。

【问题讨论】:

    标签: python list if-statement list-comprehension


    【解决方案1】:

    您可以使用嵌套生成器表达式只调用一次函数:

    [(x, fx) for (x, fx) in ((x, f(x)) for x in list_x) if fx == cond(x)]
    

    生成器表达式以同步方式迭代以生成(x, fx) 元组用于列表理解。

    如果您觉得这对读者来说更容易,您可以先将生成器表达式拆分为一个单独的名称:

    mapped_x = ((x, f(x)) for x in list_x)
    filtered_x = [(x, fx) for (x, fx) in mapped_x if fx == cond(x)]
    

    重申这一点:生成器表达式是惰性执行的;对于for ... in mapped_x 循环中的每一步,表达式中的for 循环将逐步推进。

    演示:

    >>> list_x = range(5)
    >>> f = lambda x: print('f({!r})'.format(x)) or (x ** 2 - 1)
    >>> cond = lambda x: print('cond({!r})'.format(x)) or x % 2 == 0
    >>> mapped_x = ((x, f(x)) for x in list_x)
    >>> [(x, fx) for (x, fx) in mapped_x if fx == cond(x)]
    f(0)
    cond(0)
    f(1)
    cond(1)
    f(2)
    cond(2)
    f(3)
    cond(3)
    f(4)
    cond(4)
    [(1, 0)]
    

    注意f(x) 是如何只调用一次的,然后立即检查条件。

    这有多高效取决于f(x) 调用的成本;生成器表达式作为单独的函数框架执行,解释器将在两个框架之间切换(列表推导的循环也是框架对象)。

    如果 f(x) 是一个 Python 函数,那么您已经赢了,因为您现在将创建的函数框架对象的数量减半(每个 f(x) 调用也会创建一个框架对象,而创建这些框架对象的成本相对较高)。对于 C 函数,您应该使用 timeit module 创建一些试运行,以查看对于您预期的列表大小来说哪个更快。

    【讨论】:

      【解决方案2】:

      如果不想两次调用f,可以先将f应用到列表中

      [a for a in map(lambda x: (x, f(x)), list_x) if a[1] == cond(x)]

      【讨论】:

      • 请注意,使用 lambda 会显着减慢速度(创建和弹出函数框架对象 N 次,列表长度为 N)。
      • @MartijnPieters 我怀疑限定符是significantly。并不是说我不信任你。
      • @AnthonyKong:你会感到惊讶。试试timeit,或查看Python Function calls are really slow
      【解决方案3】:

      过滤器将是一种干净的方式。它将评估传递的函数,如果它返回 true,它将保留元素,否则,不。

      print (list(filter(lambda x: x[1] == cond(x[0]), [(x, f(x)) for x in list_x])))
      

      【讨论】:

        猜你喜欢
        • 2019-11-03
        • 2023-03-13
        • 1970-01-01
        • 2020-05-14
        • 2018-09-08
        • 2011-12-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-24
        相关资源
        最近更新 更多