5 ms·
This is what your co-worker does now: 'result: {long_var_name}'.format(long_var_name=long_var_name) A similar option is possible with '%'-style formatting:
by dalke 12y ago
This is what your co-worker does now:
'result: {long_var_name}'.format(long_var_name=long_var_name)
A similar option is possible with '%'-style formatting:
'result: %(long_var_name)s'%{"long_var_name":long_var_name}
-or-
'result: %(long_var_name)s'%dict(long_var_name=long_var_name)
The first of these alternatives is indeed shorter, so long as there's only a single parameter. If there are multiple parameters then the .format() solution will be shorter.
My experience with '%(name)s' % dict formatting is that I would often forget the terminal 's', and write it as '%(name)'. For template-like strings, where I want named substitutions, I am very much in favor of {}-style formatting.
So if your co-worker insists on named substitutions, then s.format() is less verbose than s % dict.
Regarding logging, there's a section of how to use format templates in the logging system, at https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles https://docs.python.org/3/howto/logging-cookbook.html#format... . In addition to using a LogRecord factory, you could reduce the overhead in old-style logging to only an extra constructor calls:
log.info(M('result: {} {}', one, two))
where M.__str__ forwards to str.format.
Personally, I would like a way to pre-compile the format string:
fmt = format_compile("result: {} {} {}")
for result in results:
print(fmt(*result))
because currently (in Python 3.3) "%d %d %d" is about 40% faster than "{} {} {}".
EDIT: Never mind: It can be faster to interpolate the string each time than to call a constructor:
% python3.3 -mtimeit 's="%s %s %s"' 's % (1, 3, 9)'
1000000 loops, best of 3: 0.36 usec per loop
% python3.3 -mtimeit 'class Spam:pass' 'Spam()'
10000 loops, best of 3: 23.6 usec per loop
I did not expect a factor of 65!
- zwegner 12y agoYour timeit calls in the edit need the -s parameter before the first statements, so they aren't executed on each loop iteration. The overhead is in creating the class, not the instances. $ python3 -mtimeit -s 's="%s %s %s"' 's % (1, 3, 9)' 1000000 loops, best of 3: 0.343 usec per loop $ python3 -mtimeit -s 'class Spam:pass' 'Spam()' 10000000 loops, best of 3: 0.106 usec per loop
- dalke 12y agoThanks! That's a big forehead smack on my side. The numbers are more in line with what I expected. Meaning it is possible to defer some of the time cost by using a single constructor rather than evaluating the string.
- mixmastamyk 12y agoI don't like all that verbosity in short debug text at all, no matter which syntax is used. I would have done, e.g.: print 'result:', long_var_name I do like your idea of a custom formatter though, perhaps it could be installed as a formatter into the logger beforehand, getting the slightly improved syntax without frequent object creation.
- dalke 12y agoRight, but the verbosity here is primarily due to your co-worker, given that the guy at your work would likely have used %(name)s instead of {name}. Regarding logging, the docs suggest that setting your own LogRecord factory is the way to go if that's what you want.
- mixmastamyk 12y agoStill, with % you can skip the .format() and while logging you can even skip the %. If {} was more "built-in" with an operator/logging I think it'd be a clearer win.
- dalke 12y agoMy point is that even with the ".format()", if you use named arguments then .format() is shorter than '%' if you have two or more terms: "%(name1)s %(name2)s"%{"name1":"ABC","name2":"DEF"} "{name1} {name2}.format(name1="ABC",name2="DEF") To get what you want, you need to convince your co-worker to 1) switch to positional arguments, and 2) switch to '%' instead of .format. Even if Python never gained the .format() option, so #2 weren't an issue, you would still be stuck with #1, because '%' supported them as well. As for logging, I pointed out two possible ways to address the problem. Personally, I don't log in performance critical loop since Python's function call overhead is so high. Testing now, you can see that 3/4ths of the overhead for logging a simple format statement is just in calling the logger: % python3.3 -mtimeit -s 'import logging' 'logging.info' 10000000 loops, best of 3: 0.0525 usec per loop % python3.3 -mtimeit -s 'import logging' 'logging.info("abc")' 1000000 loops, best of 3: 1.59 usec per loop % python3.3 -mtimeit -s 'import logging' 'logging.info("abc %d %d %d", 1, 2, 3)' 1000000 loops, best of 3: 1.71 usec per loop % python3.3 -mtimeit -s 'import logging' 'logging.info("abc %d %d %d"%(1, 2, 3))' 1000000 loops, best of 3: 1.64 usec per loop % python3.3 -mtimeit -s 'import logging' 'logging.info("abc %d %d %d".format(1, 2, 3))' 1000000 loops, best of 3: 1.99 usec per loop According to this, calling info() with more than one argument is actually slower than calling '%' every time(!). Is your objection based on a measured performance impact (eg, more complicated formats will be worse) or a theoretical evaluation?