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

tom*_*sen 4 python list-comprehension

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

l = [line.split()[i] for i in indexes]
Run Code Online (Sandbox Code Playgroud)

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

l = line.rstrip().split()
l = [l for i in indexes]
Run Code Online (Sandbox Code Playgroud)

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

Mar*_*ers 5

列表理解中左侧的表达式针对每个元素重新评估,是的.

如果您只需要评估一次,您需要完成您所做的事情; 首先调用它并存储要在列表推导中重复使用的结果.

列表显示文档:

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

强调我的.

您还可以使用以下dis.dis()函数反汇编列表解析:

>>> 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        
Run Code Online (Sandbox Code Playgroud)

FOR_ITER操作码开始循环(与JUMP_ABSOLUTE关闭它),每一次一个LOAD_NAME line,LOAD_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])).

  • @ tommy.carstensen:另一位社区成员只是在这方面受骗,大概是因为他们觉得这个答案更好地涵盖了基础. (2认同)