Edit: In C, the version that loops is 15 times faster than the version that allocates a new string. Python is weird.
In [1]: dl = lambda n: 1 if n < 10 else 1 + dl(n // 10)
In [3]: map(dl, [0, 1, 9, 10, 99, 1000, 15432, 32, 801])
Out[3]: [1, 1, 1, 2, 2, 4, 5, 2, 3]
In [4]: %timeit dl(15322)
100000 loops, best of 3: 4.64 µs per loop
In [5]: %timeit len(str(15322))
1000000 loops, best of 3: 1.41 µs per loop
In [6]: %timeit dl(0)
1000000 loops, best of 3: 721 ns per loop
In [7]: %timeit len(str(0))
1000000 loops, best of 3: 1.24 µs per loopSo, basically, it's only interpreting a very small number of interpreter bytecodes either way, so the small number it has to interpret to use the builtins is comparable to the small number it has to interpret to run the recursive definition, and so the interpretive overhead is comparable (and it swamps the overhead of things like allocating a new string).
This machine is kind of slow. This took 54 CPU seconds in LuaJIT:
> function dl(n) if n < 10 then return 1 else return 1 + dl(n/10) end end
> for i = 1, 1000*1000*100 do dl(15322) end
That means that approach took 540 ns per invocation rather than Python's 4640 ns --- only about 9× slower instead of the usual 40×. Or maybe this is a case where LuaJIT isn't really coming through the way it usually does.https://github.com/python/cpython/blob/master/Objects/floato...