Home > other >  Does using "for i in range(len(nums))" calculate length of nums for every iteration?
Does using "for i in range(len(nums))" calculate length of nums for every iteration?

Time:12-06

I want to print every number and index:

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])
      

Out of these two codes which one is efficient or are they same?

CodePudding user response:

The best way is do it using enumerate function:

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

CodePudding user response:

Both examples will result in the same byte code, except for the fact that the second option also stores the length in a separate variable. So both are effectively identical and there will be no noticeable impact from using one over the other.

The reason for this is btw. that the iteration target, i.e. range(len(nums)) or range(length) is only executed once at the beginning of your loop. So that code never runs more than once, so it doesn’t matter whether you execute that code outside of the for loop syntax, or within.

CodePudding user response:

According to the CPython language reference, it is only computed once (emphasis mine):

The for statement is used to iterate over the elements of a sequence (such as a string, tuple or list) or other iterable object:

for_stmt ::= "for" target_list "in" expression_list ":" suite ["else" ":" suite]

The expression list is evaluated once; it should yield an iterable object. An iterator is created for the result of the expression_list.

CodePudding user response:

You can diassemble and compare yourself:

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)

And see:

# 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)

versus

# 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 

Identically (only the storing of len in a variable differs). I commented the printing for ease of demonstration - it is the same in both. So f2 stores the len in a const in addition to what f1 does - so no noticeable timewise impact - and not reevaluating len(nums) multiple times.

  • Related