Python:在列表推导中多次评估split函数?

时间:2015-08-30 13:50:05

标签: python list-comprehension

有一段时间我一直想知道的事情。在此列表理解中,拆分是执行一次还是多次?

l = [line.split()[i] for i in indexes]

我目前以这种方式列出这样的理解:

l = line.rstrip().split()
l = [l for i in indexes]

但我不确定,是否有必要。除了是/否答案,我肯定想知道,我可以通过CPU分析或阅读一些文档来了解自己。感谢。

3 个答案:

答案 0 :(得分:5)

对每个元素重新评估列表推导左侧的表达式,是的。

如果您只需要评估一次,那么您需要完成您的工作;首先调用它并存储要在列表推导中重复使用的结果。

来自List displays documentation

  

在这种情况下,新列表的元素是通过将每个forif子句视为块,从左到右嵌套,和评估而生成的元素。每次到达最里面的块时生成列表元素的表达式

强调我的。

您还可以使用dis.dis() function

反汇编列表理解
>>> import dis
>>> dis.dis(compile('[line.split()[i] for i in indexes]', '', 'eval'))
  1           0 BUILD_LIST               0
              3 LOAD_NAME                0 (indexes)
              6 GET_ITER            
        >>    7 FOR_ITER                22 (to 32)
             10 STORE_NAME               1 (i)
             13 LOAD_NAME                2 (line)
             16 LOAD_ATTR                3 (split)
             19 CALL_FUNCTION            0
             22 LOAD_NAME                1 (i)
             25 BINARY_SUBSCR       
             26 LIST_APPEND              2
             29 JUMP_ABSOLUTE            7
        >>   32 RETURN_VALUE        

FOR_ITER操作码启动循环(JUMP_ABSOLUTE关闭它),每次执行LOAD_NAME lineLOAD_ATTR splitCALL_FUNCTION。换句话说,字节码13到19实现了line.split()部分,并且每次通过循环执行它,该循环从字节码7到29运行。

(Python 3注意:列表推导有自己的范围,你需要从外部代码对象常量中提取代码对象; dis.dis(compile('[line.split()[i] for i in indexes]', '', 'eval').co_consts[0]))。

答案 1 :(得分:1)

我要补充一点,您的LC示例可以替代:

<input type="button" onclick="FormatApplicationMessage(@application.StatusID, '@application.IssueMessage')" class="fa fa-search fa-lg" />

因此,答案肯定是肯定的,每次迭代都会对其进行评估。

答案 2 :(得分:0)

就像@Dalen所说的那样,在推理列表理解时,我相信您可以期望它的行为就像您在没有理解的情况下完成相同的事情一样。 @Martijn展示了如何通过查看程序集来验证这一点。

我的答案

  1. 提供了一种更简单的方法来亲自验证行为(在某种意义上,您无需阅读汇编)。

  2. 在列表理解范围内的多个位置显示一个函数的行为(当我想知道“外部函数”(见下文)的调用频率时发现了这个问题。)

代码:

def inner_func(i):
    print('called inner')
    return i

def outer_func(n):
    print('called outer')
    return range(n)

l = [inner_func(i) for i in outer_func(5)]

这将打印一次called outercalled inner 5次,验证是否像正常的for循环一样,一次执行外部函数,一次执行一次内部函数。