Python is not known to be a very efficient language to execute. In addition, looping is a very time-consuming operation in any language. If any simple single-step operation takes 1 unit of time, repeating the operation tens of thousands of times will eventually increase the time spent tens of thousands of times.
while
and for
are two keywords commonly used in Python to implement loops, there is a real difference in their efficiency. For example, the following test code.
import timeit
def while_loop(n=100_000_000):
i = 0
s = 0
while i < n:
s += i
i += 1
return s
def for_loop(n=100_000_000):
s = 0
for i in range(n):
s += i
return s
def main():
print('while loop\t\t', timeit.timeit(while_loop, number=1))
print('for loop\t\t', timeit.timeit(for_loop, number=1))
if __name__ == '__main__':
main()
# => while loop 4.718853999860585
# => for loop 3.211570399813354
This is a simple summation operation that computes the sum of all natural numbers from 1 to n. You can see that the for
loop is 1.5 seconds faster than the while
loop.
The difference is mainly due to the different mechanics of the two.
In each loop, while
actually performs two more steps than for
: a bounds check and the self-incrementing of variable i
. That is, for each loop, while
performs two more steps than for
. That is, for each loop, while does a bounds check (while i < n
) and a self-increment calculation (i += 1
). Both of these operations are explicitly pure Python code.
The for
loop does not require a bounds check and self-increment operation, and adds no explicit Python code (pure Python code is less efficient than the underlying C code). When the number of loops is large enough, a significant efficiency gap emerges.
Two more functions can be added to add unnecessary bounds checking and self-incrementing to the for
loop.
import timeit
def while_loop(n=100_000_000):
i = 0
s = 0
while i < n:
s += i
i += 1
return s
def for_loop(n=100_000_000):
s = 0
for i in range(n):
s += i
return s
def for_loop_with_inc(n=100_000_000):
s = 0
for i in range(n):
s += i
i += 1
return s
def for_loop_with_test(n=100_000_000):
s = 0
for i in range(n):
if i < n:
pass
s += i
return s
def main():
print('while loop\t\t', timeit.timeit(while_loop, number=1))
print('for loop\t\t', timeit.timeit(for_loop, number=1))
print('for loop with increment\t\t',
timeit.timeit(for_loop_with_inc, number=1))
print('for loop with test\t\t', timeit.timeit(for_loop_with_test, number=1))
if __name__ == '__main__':
main()
# => while loop 4.718853999860585
# => for loop 3.211570399813354
# => for loop with increment 4.602369500091299
# => for loop with test 4.18337869993411
As you can see, the addition of the bounds check and self-increment operations does significantly affect the efficiency of the for
loop.
As mentioned earlier, Python’s underlying interpreter and built-in functions are implemented in C. C is much more efficient than Python.
For the above sum of equal variables operation, Python’s built-in sum
function can be used to obtain a much more efficient execution than a for
or while
loop.
import timeit
def while_loop(n=100_000_000):
i = 0
s = 0
while i < n:
s += i
i += 1
return s
def for_loop(n=100_000_000):
s = 0
for i in range(n):
s += i
return s
def sum_range(n=100_000_000):
return sum(range(n))
def main():
print('while loop\t\t', timeit.timeit(while_loop, number=1))
print('for loop\t\t', timeit.timeit(for_loop, number=1))
print('sum range\t\t', timeit.timeit(sum_range, number=1))
if __name__ == '__main__':
main()
# => while loop 4.718853999860585
# => for loop 3.211570399813354
# => sum range 0.8658821999561042
As you can see, using the built-in sum
function instead of a loop increases the efficiency of code execution exponentially.
The sum operation of the built-in function is actually a loop, but it is implemented in C, whereas the sum
operation in the for
loop is implemented in pure Python code s += i
. C > Python.
Expand your thinking a bit. As a child, you’ve heard the story of the childhood Gaussian who cleverly calculated the sum of 1 to 100. 1…100 equals (1 + 100) * 50. This same calculation can be applied to the summation operation above.
import timeit
def while_loop(n=100_000_000):
i = 0
s = 0
while i < n:
s += i
i += 1
return s
def for_loop(n=100_000_000):
s = 0
for i in range(n):
s += i
return s
def sum_range(n=100_000_000):
return sum(range(n))
def math_sum(n=100_000_000):
return (n * (n - 1)) // 2
def main():
print('while loop\t\t', timeit.timeit(while_loop, number=1))
print('for loop\t\t', timeit.timeit(for_loop, number=1))
print('sum range\t\t', timeit.timeit(sum_range, number=1))
print('math sum\t\t', timeit.timeit(math_sum, number=1))
if __name__ == '__main__':
main()
# => while loop 4.718853999860585
# => for loop 3.211570399813354
# => sum range 0.8658821999561042
# => math sum 2.400018274784088e-06
The final execution time of math sum is about 2.4e-6
, which is a million times shorter. The idea here is that since loops are inefficient, a piece of code has to be executed hundreds of millions of times over.
So we just don’t need to loop, and use mathematical formulas to turn hundreds of millions of loops into a single step operation. The efficiency is naturally enhanced to an unprecedented degree.
Final conclusion (a bit riddler).
The fastest way to implement loops – is to not use them
For Python, use built-in functions whenever possible to minimize the pure Python code in the loop.
Of course, built-in functions aren’t the fastest in some cases. When creating lists, for example, it’s the literal writing that’s faster.
Source: https://www.starky.ltd/2021/11/23/the-fastest-way-to-loop-in-python https://mp.weixin.qq.com/s/lJcl-4Xwb9XYEZNG9kuimg