I recently answered a question on a sister site which asked for a function that counts all even digits of a number. One of the other answers contained two functions (which t
All your functions contain equal number of calls to str(n) (one call) and c in "02468" (for every c in n). Since then I would like to simplify:
import timeit
num = ''.join(str(i % 10) for i in range(1, 10000001))
def count_simple_sum():
return sum(1 for c in num)
def count_simple_for():
count = 0
for c in num:
count += 1
return count
print('For Loop Sum:', timeit.timeit(count_simple_for, number=10))
print('Built-in Sum:', timeit.timeit(count_simple_sum, number=10))
sum is still slower:
For Loop Sum: 2.8987821330083534
Built-in Sum: 3.245505138998851
The key difference between these two functions is that in count_simple_for you are iterating only throw num with pure for loop for c in num, but in count_simple_sum your are creating a generator object here (from @Markus Meskanen answer with dis.dis):
3 LOAD_CONST 1 ( at 0x10dcc8c90, file "test.py", line 14>)
6 LOAD_CONST 2 ('count2..')
sum is iterating over this generator object to sum the elements produced, and this generator is iterating over elements in num to produce 1 on each element. Having one more iteration step is expensive because it requires to call generator.__next__() on each element and these calls are placed into try: ... except StopIteration: block which also adds some overhead.