[Python-3000] PEP 3101 clarification requests
Eric Smith
eric+python-dev at trueblade.com
Tue Aug 21 11:55:23 CEST 2007
Greg Ewing wrote:
> Guido van Rossum wrote:
>> But how often will you need this? (You only need the !s part if you
>> don't know that the argument is a string.)
>
> Maybe I'm confused. I thought we had agreed that most
> types would delegate to str if they didn't understand
> the format, so most of the time there wouldn't be any
> need to use "!s". Is that still true?
Yes, it is true. Here's a working test case:
# class with __str__, but no __format__
class E:
def __init__(self, x):
self.x = x
def __str__(self):
return 'E(' + self.x + ')'
self.assertEqual('{0}'.format(E('data')), 'E(data)')
self.assertEqual('{0:^10}'.format(E('data')), ' E(data) ')
self.assertEqual('{0:^10s}'.format(E('data')), ' E(data) ')
The formatting in all 3 cases is being done by string.__format__()
(actually object.__format__, which calls str(o).__format__).
> If not, I think it will be very inconvenient, as I
> very frequently format things of all sorts of types
> using "%s", and rely on it doing something reasonable.
That will continue to work, for objects that don't provide a __format__
function. The problem is that if an object does does its own
__format__, it either needs to understand all of the string formatting,
or at least recognize a string format and send it along to
string.__format__() (or object.__format__, which will convert to string
for you). Another working test case:
# class with __format__ that forwards to string,
# for some format_spec's
class G:
def __init__(self, x):
self.x = x
def __str__(self):
return "string is " + self.x
def __format__(self, format_spec):
if format_spec == 's':
return 'G(' + self.x + ')'
return object.__format__(self, format_spec)
self.assertEqual('{0:s}'.format(G('data')), 'G(data)')
# unknown spec, will call object.__format__, which calls str()
self.assertEqual('{0:>15s}'.format(G('data')), ' string is data')
# convert to string explicitely, overriding G.__format__
self.assertEqual('{0!s}'.format(G('data')), 'string is data')
Note the collision with the 's' format_spec in this example. You'd have
to carefully design your object's __format__ specifiers to be able to
recognize string specifiers as being different from own specifiers
(something that G does not cleanly do).
int is like G: it defines its own __format__. "!s" says: skip the
object's own __format__ function, just convert the object to a string
and call string.__format__. So what Guido is saying is that for int,
instead of having int.__format__ recognize string formatting specifiers
and doing the conversion to string, you need to convert it to a string
yourself with "!s".
Whether that's better or not, I leave up to Guido. I personally think
that for int and float, having them recognize "s" format specs is
sufficiently handy that it's worth having, but I understand not
providing that feature.
Eric.
More information about the Python-3000
mailing list