>>> 'string with no string formatting markers' % ['string']
'string with no string formatting markers'
>>> 'string with no string formatting markers' % ('string',)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
I would expect both cases to raise a TypeError, but this is not the case. Why not?
The Python documentation on this subject talks about strings, tuples and dictionaries, but says nothing about lists. I’m a bit confused about this behavior. I’ve been able to duplicate it in Python 2.7 and 3.2.
Reading carefully, the documentation states that:
Now, in this case the
formatdoes not require a single argument and thus the documentation tells us that you should use atupleor a mapping as argument; other cases fall in “undefined behaviour”(which is what is happening: the behaviour is not consistent in all cases).This should probably be considered the final answer to the question: if the string does not have any format specifier, using a
list(or any kind different fromtupleor a mapping) should simply be considered a bug by itself leading to undefined behaviour.From this follows that you ought to always use a
tupleordictas argument, otherwise you have to check for format specifiers by hand or handle odd behaviours.In your case you can probably fix the problem using
(['string'], )instead of['string'].Possible “explanation” of why the resultant behaviour seems to be so random:
It seems like there was a buggy check in the original implementation of
PyString_Format/PyUnicode_Format, instead of usingPyMappingCheckon this line:It was used this code:
which is not equivalent. For example
setdoes not havetp_as_mappingset(at least in the Python2.7.3 source code that I have downloaded some weeks ago), whilelistdoes set it.This might be the reason why
list(and possibly other objects) do not raise theTypeErrorwhile,set,intand many others do.As I stated before in this same answer I do get
TypeErroreven withlists:This probably shows that the above issue is not the only one here.
Looking at the source code I agree that, in theory, the number of arguments is not checked if the argument is not a tuple, but this would imply
'some string' % 5 -> 'some string'and not aTypeError, so there must be something fishy in that code.