【问题标题】:Does using "for i in range(len(nums))" calculate length of nums for every iteration?是否使用“for i in range(len(nums))”计算每次迭代的 nums 长度?
【发布时间】:2021-12-05 12:10:09
【问题描述】:

我想打印每个数字和索引:

nums = [3,2,1,5,6,4]

#1st code:
for i in range(len(nums)):
    print(i,nums[i])

#2nd code:
length = len(nums)
for i in range(length):
    print(i,nums[i])
      

在这两个代码中,哪一个是有效的还是相同的?

【问题讨论】:

    标签: python python-3.x list


    【解决方案1】:

    最好的方法是使用enumerate函数:

    nums = [3, 2, 1, 5, 6, 4]
    for index, number in enumerate(nums):
        print(index, number)
    

    【讨论】:

      【解决方案2】:

      这两个示例将产生相同的字节码,除了第二个选项还将长度存储在一个单独的变量中。因此,两者实际上是相同的,使用其中一个不会产生明显的影响。

      原因是顺便说一句。迭代目标,即range(len(nums))range(length) 仅在循环开始时执行一次。因此,该代码永远不会运行超过一次,因此无论您是在 for 循环语法之外还是在其中执行该代码都无关紧要。

      【讨论】:

        【解决方案3】:

        根据CPython language reference,它只计算一次(强调我的):

        for 语句用于遍历序列的元素 (如字符串、元组或列表)或其他可迭代对象:

        for_stmt ::= "for" target_list "in" expression_list ":" 套件 ["else" ":" 套件]

        表达式列表计算一次;它应该产生一个可迭代的 目的。为 expression_list 的结果创建一个迭代器。

        【讨论】:

          【解决方案4】:

          大家可以自行拆解对比:

          nums = [3,2,1,5,6,4]
          
          # 1st code:
          def f1():
              for i in range(len(nums)):
                  pass # print(i,nums[i])
          
          #2nd code:
          def f2():
              length = len(nums)
              for i in range(length):
                  pass # print(i,nums[i])
              
          import dis
          
          dis.dis(f1)
          dis.dis(f1)
          

          然后看看:

          # f1  -----
            5           0 LOAD_GLOBAL              0 (range)
                        2 LOAD_GLOBAL              1 (len)
                        4 LOAD_GLOBAL              2 (nums)
                        6 CALL_FUNCTION            1
                        8 CALL_FUNCTION            1
                       10 GET_ITER
                  >>   12 FOR_ITER                 2 (to 18)
                       14 STORE_FAST               0 (i)
          
            6          16 JUMP_ABSOLUTE            6 (to 12)
          

          # f2  -----
          
            5     >>   18 LOAD_CONST               0 (None)       # storing len
                       20 RETURN_VALUE                            # in variable
            5           0 LOAD_GLOBAL              0 (range)
                        2 LOAD_GLOBAL              1 (len)
                        4 LOAD_GLOBAL              2 (nums)
                        6 CALL_FUNCTION            1
                        8 CALL_FUNCTION            1
                       10 GET_ITER
                  >>   12 FOR_ITER                 2 (to 18)
                       14 STORE_FAST               0 (i)
          
            6          16 JUMP_ABSOLUTE            6 (to 12)
          
            5     >>   18 LOAD_CONST               0 (None)
                       20 RETURN_VALUE 
          

          相同(只有 len 在变量中的存储不同)。为了便于演示,我评论了印刷 - 两者都是一样的。因此,f2 除了 f1 所做的之外,还将 len 存储在 const 中 - 因此没有明显的时间影响 - 并且不会多次重新评估 len(nums)

          【讨论】:

            猜你喜欢
            • 2017-11-05
            • 2019-11-30
            • 1970-01-01
            • 1970-01-01
            • 2020-11-04
            • 1970-01-01
            • 2018-02-11
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多