Этот вопрос и мой ответ заставили меня задуматься об этом своеобразном различии между Python 2.7 и Python 3.4. Возьмем простой пример кода:
import timeit
import dis
c = 1000000
r = range(c)
def slow():
for pos in range(c):
r[pos:pos+3]
dis.dis(slow)
time = timeit.Timer(lambda: slow()).timeit(number=1)
print('%3.3f' % time)
В Python 2.7 я последовательно получаю 0.165~
, а для Python 3.4 я последовательно получаю 0.554~
. Единственное существенное различие между дизассемблиями заключается в том, что Python 2.7 испускает SLICE+3
байтовый код, в то время как Python 3.4 испускает BUILD_SLICE
, а затем BINARY_SUBSCR
. Обратите внимание, что я удалил кандидатов на потенциальное замедление от другого вопроса, а именно, строки и тот факт, что xrange
не существует в Python 3.4 (который должен быть похож на последний range
class anyways).
Использование itertools'
islice
дает почти одинаковые тайминги между ними, поэтому я очень подозреваю, что это нарезка, что причина разницы здесь.
Почему это происходит и есть ли ссылка на авторитетный источник, документирующий изменение в поведении?
EDIT: В ответ на ответ я обернул объекты range
в list
, что дало заметное ускорение. Однако, когда я увеличил количество итераций в timeit
, я заметил, что разницы во времени стали больше и больше. В качестве проверки на работоспособность я заменил срез на None
, чтобы увидеть, что произойдет.
500 итераций в timeit
.
c = 1000000
r = list(range(c))
def slow():
for pos in r:
None
дает 10.688
и 9.915
соответственно. Замена цикла for на for pos in islice(r, 0, c, 3)
дает 7.626
и 6.270
соответственно. Заменив None
на r[pos]
, получим 20~
и 28~
соответственно. r[pos:pos+3]
дает 67.531
и 106.784
соответственно.
Как вы можете видеть, разница во времени огромна. Опять же, я все еще уверен, что проблема не связана напрямую с range
.