Steven Barker added the comment: The behavior of !s with the format() methods isn't exactly the same as %s with % formatting. With the latter, the conversion depends on the type of the result string, which in turn depends on whether the format string *or any of the values values* is unicode: >>> class X(): def __str__(self): return "str" def __unicode__(self): return u"unicode" >>> "%s %s" % ("foo", X()) 'foo str' >>> "%s %s" % (u"foo", X()) u'foo unicode' >>> u"%s %s" % ("foo", X()) u'foo unicode' >>> u"%s %s" % (u"foo", X()) u'foo unicode' The format methods are more consistent, always returning the same type as the format string regardless of the types of the arguments (and using the appropriate converter): >>> "{} {!s}".format("foo", X()) 'foo str' >>> "{} {!s}".format(u"foo", X()) 'foo str' >>> u"{} {!s}".format("foo", X()) u'foo unicode' >>> u"{} {!s}".format(u"foo", X()) u'foo unicode' The documentation for %s conversion (in the second table here: https://docs.python.org/2/library/stdtypes.html#string-formatting-operations ) also suggests that it always uses str(), though the footnote for that table entry alludes to the behavior shown above without ever mentioning using unicode() for conversions explicitly. ---------- nosy: +Steven.Barker _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue21547> _______________________________________