[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