[Python-Dev] optimization required: .format() is much slower than %

Nick Coghlan ncoghlan at gmail.com
Tue May 27 11:14:54 CEST 2008


Following Terry's suggestion, I repeated Christian's tests with the 
lookup of the format method taken outside the loop (since one advantage 
of the new approach is to make that micro-optimisation easier), and also 
tried a few additional examples.

First, there seems to be about a 0.25 microsecond hit (on my machine) 
which reflects the impact of the lookup of the "format" attribute itself.

Secondly, the string % operator appears to have an explicit optimisation 
for the 'just return str(self)' case. This optimisation is missing from 
the new string format method.

The only optimisation idea I came up with (other than the addition of a 
tp_format slot) is for string objects to be able to cache their 
(lookup:subformat) pairs rather than having to parse themselves every 
time. That has obvious memory consumption implications though.

Cheers,
Nick.

Test results:

# No formatting at all, just the method invocation:
$ ./python -m timeit "''.format()"
1000000 loops, best of 3: 0.635 usec per loop
$ ./python -m timeit -s "fmt = '%s'.format" "fmt()"
1000000 loops, best of 3: 0.48 usec per loop
$ ./python -m timeit "'' % ()"
1000000 loops, best of 3: 0.389 usec per loop

# Format one argument by position
$ ./python -m timeit "'{0}'.format('nothing')"
1000000 loops, best of 3: 1.56 usec per loop
$ ./python -m timeit -s "fmt = '{0}'.format" "fmt('nothing')"
1000000 loops, best of 3: 1.44 usec per loop
$ ./python -m timeit "'%s' % 'nothing'"
10000000 loops, best of 3: 0.0736 usec per loop

# Format one non-string argument by position
$ ./python -m timeit "'{0}'.format(0)"
100000 loops, best of 3: 1.74 usec per loop
$ ./python -m timeit -s "fmt = '{0}'.format" "fmt(0)"
1000000 loops, best of 3: 1.51 usec per loop
$ ./python -m timeit "'%s' % 0"
10000000 loops, best of 3: 0.0987 usec per loop

# Format one argument by position with additional text
$ ./python -m timeit "'some text with {0}'.format('nothing')"
1000000 loops, best of 3: 1.7 usec per loop
$ ./python -m timeit -s "fmt = 'some text with {0}'.format" "fmt('nothing')"
1000000 loops, best of 3: 1.45 usec per loop
$ ./python -m timeit "'some text with %s' % 'nothing'"
1000000 loops, best of 3: 0.612 usec per loop

# Format two arguments by position with additional text
$ ./python -m timeit "'some text with {0} {1}'.format('nothing', 'more')"
100000 loops, best of 3: 2.63 usec per loop
$ ./python -m timeit -s "fmt = 'some text with {0} {1}'.format" 
"fmt('nothing', 'more')"
100000 loops, best of 3: 2.31 usec per loop
$ ./python -m timeit "'some text with %s %s' % ('nothing', 'more')"
1000000 loops, best of 3: 0.804 usec per loop

# Format two non-string arguments by position with additional text
$ ./python -m timeit "'some text with {0} {1}'.format(0, 1)"
100000 loops, best of 3: 2.81 usec per loop
$ ./python -m timeit -s "fmt = 'some text with {0} {1}'.format" "fmt(0, 1)"
100000 loops, best of 3: 2.46 usec per loop
$ ./python -m timeit "'some text with %s %s' % (0, 1)"
1000000 loops, best of 3: 0.851 usec per loop

# Format two non-string arguments by name with additional text
$ ./python -m timeit -s "d = dict(a=0, b=1)" "'some text with {a} 
{b}'.format(**d)"
100000 loops, best of 3: 2.81 usec per loop
$ ./python -m timeit -s "d = dict(a=0, b=1)" -s "fmt = 'some text with 
{a} {b}'.format" "fmt(**d)"
100000 loops, best of 3: 2.58 usec per loop
$ ./python -m timeit -s "d = dict(a=0, b=1)" "'some text with %(a)s 
%(b)s' % (d)"
1000000 loops, best of 3: 1 usec per loop

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-Dev mailing list