range
включает в себя небольшое количество фиксированных накладных расходов (для поиска range
, сначала в глобальных, затем во встроенных модулях, затем в стоимости отправки общего вызова функции и выделения / инициализации объекта);если n
достаточно мало, оно не будет компенсировано сниженной стоимостью за цикл:
In [1]: %%timeit -r5 n = 3
...: for i in range(n):
...: pass
...:
365 ns ± 15.1 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
In [2]: %%timeit -r5 n = 3
...: i = 0
...: while i < n:
...: i += 1
...:
252 ns ± 16.9 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
Но когда n
достигает даже умеренного размера, уменьшенные накладные расходы на элемент окупаются:
In [3]: %%timeit -r5 n = 10
...: for i in range(n):
...: pass
...:
461 ns ± 18.1 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
In [4]: %%timeit -r5 n = 10
...: i = 0
...: while i < n:
...: i += 1
...:
788 ns ± 73.6 ns per loop (mean ± std. dev. of 5 runs, 1000000 loops each)
range
включает более высокие постоянные затраты, но более низкие затраты на единицу, вот и все.