Вычисляет ли использование «для i в диапазоне (len (nums))» длину чисел для каждой итерации?

#python #python-3.x #list

#python #python-3.x #Список

Вопрос:

Я хочу напечатать каждое число и индекс:

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

Какой из этих двух кодов эффективен или они одинаковы?

Ответ №1:

Лучший способ сделать это с помощью enumerate функции:

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

Ответ №2:

Оба примера приведут к одному и тому же байт-коду, за исключением того факта, что второй вариант также сохраняет длину в отдельной переменной. Таким образом, оба они фактически идентичны, и использование одного над другим не окажет заметного влияния.

Причина этого, кстати. что цель итерации, т.Е. range(len(nums)) or range(length) , выполняется только один раз в начале вашего цикла. Таким образом, этот код никогда не выполняется более одного раза, поэтому не имеет значения, выполняете ли вы этот код вне синтаксиса цикла for или внутри.

Ответ №3:

Согласно ссылке на язык CPython, он вычисляется только один раз (курсив мой):

Оператор for используется для перебора элементов последовательности (например, строки, кортежа или списка) или другого итеративного объекта:

for_stmt ::= «для» target_list «в» expression_list «:» suite [«else» «:» suite]

Список выражений вычисляется один раз; он должен выдавать итеративный объект. Для результата 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 что сохраняет len в const в дополнение к тому, что f1 делает — так что никакого заметного влияния во времени — и не пересматривает len(nums) несколько раз.