String concatenation vs. string formatting

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Jul 9 01:12:39 EDT 2011


Andrew Berg wrote:

> Is it bad practice to use this
>> logger.error(self.preset_file + ' could not be stored - ' +
>> sys.exc_info()[1])
> Instead of this?
>> logger.error('{file} could not be stored -
>> {error}'.format(file=self.preset_file, error=sys.exc_info()[1]))
> 
> 
> Other than the case where a variable isn't a string (format() converts
> variables to strings, automatically, right?) 

Not exactly, but more or less. format() has type codes, just like % string
interpolation:


>>> '{0:d}'.format(1)
'1'
>>> '{0:d}'.format(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Unknown format code 'd' for object of type 'str'

>>> '%d' % 1
'1'
>>> '%d' % None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: %d format: a number is required, not NoneType

If you don't give a type code, format converts any object to string (if
possible).


> and when a variable is used 
> a bunch of times, concatenation is fine, but somehow, it seems wrong.

I don't like long chains of string concatenation, but short chains seem okay
to me. One or two plus signs seems fine to my eyes, three at the most. Any
more than that, I'd look at replacing it with % interpolation, the
str.join() idiom, the string.Template class, or str.format. 

That's five ways of building strings.

Of course, *repeated* string concatenation risks being slow -- not just a
little slow, but potentially MASSIVELY slow, hundreds or thousands of times
slower that alternatives. Fortunately recent versions of CPython tend to
avoid this (which makes it all the more mysterious when the slow-down does
strike), but other Pythons like Jython and IronPython may not. So it's best
to limit string concatenation to one or two strings.

And finally, if you're concatenating string literals, you can use implicit
concatenation (*six* ways):

>>> s = ("hello "
...      "world"
...      "!")
>>> s
'hello world!'


> Sorry if this seems a bit silly, but I'm a novice when it comes to
> design. Plus, there's not really supposed to be "more than one way to do
> it" in Python.

On the contrary -- there are many different examples of "more than one way
to do it". The claim that Python has "only one way" to do things comes from
the Perl community, and is wrong.

It is true that Python doesn't deliberately add multiple ways of doing
things just for the sake of being different, or because they're cool,
although of course that's a subjective judgement. (Some people think that
functional programming idioms such as map and filter fall into that
category, wrongly in my opinion.) In any case, it's clear that Python
supports many ways of doing "the same thing", not all of which are exactly
equivalent:

# e.g. copy a list
blist = list(alist)
blist = alist[:]
blist[:] = alist  # assumes blist already exists
blist = copy.copy(alist)
blist = copy.deepcopy(alist)
blist = []; blist.extend(alist)
blist = [x for x in alist]  # don't do this


Hardly "only one way" :)



-- 
Steven




More information about the Python-list mailing list