A reminder: string concatenation really is string concatenation
Once upon a time when I was starting to write Python, I scribbled down the following code:
def warn(s): sys.stderr.write(sys.argv[0] + ": " + s + "\n")
(More or less. My actual code had an error and so didn't even work.)
Many Python programmers are wincing, because of course string
concatenation is both somewhat inefficient and not the idiomatic way to
do this; you should be using %
string formatting. But there's another
somewhat more subtle reason to avoid code like this, one that I ran into
recently when I stumbled over this code the hard way by having it blow up
in my face.
The surrounding code went something like this:
try: o, r = getopt.getopt(....) except getopt.error, cause: warn(cause) ....
This failed. You see, the subtle problem with string concatenation is
that it really is string concatenation. Unlike %
formatting, it will
not try to str()
objects to convert them to strings; if they are not
strings already, it just fails. It is of course easy to overlook this if
you usually give your code actual strings; passing in a non-string object
that can be stringified may be an uncommon corner case that you don't
test explicitly.
This code actually exposes an interesting effect of Python's slow
changes between Python 1.x and Python 2. Back in the old days exceptions
actually were strings instead of objects that can be string-ified, and
so this code could work when fed one of those exceptions. I wrote the
program this code appears in back in 2003 or earlier and I believe we
were still using Python 1.5 at the time (although it wasn't the current
version even then); the 1.5.2 version of the getopt
module appears to
still have been using string exceptions at the time. So this might have
been less crazy back then than it appears now (although it was still the
wrong way to do it plus my actual implementation had a bug).
|
|