[Python-3000] PEP - string.format

Ian Bicking ianb at colorstudy.com
Sun Apr 23 21:06:51 CEST 2006


Nick Coghlan wrote:
> [...]
>> The second method, 'fformat', is identical to the first, except that it
>> takes an additional first argument that is used to specify a 'custom
>> formatter' object, which can override the normal formatting rules for
>> specific fields:
>>
>> "More on {0}, {1}, and {c}".fformat( formatter, a, b, c=d )
>>
>> Note that the formatter is *not* counted when numbering fields, so 'a' is
>> still considered argument number zero.
> 
> I don't like this. Formatting with a different formatter should be done as a 
> method on the formatter object, not as a method on the string.

+1.  Plus "fformat" doesn't really mean anything as a name (as least to me).

But this should perform pretty well if it's going to replace % (which
wouldn't have to happen for Python 2.6, but should for py3k).


> [...]
>> Braces can be escaped using a backslash:
>>
>> "My name is {0} :-\{\}".format( 'Fred' )
> 
> So "My name is 0} :-\{\}".format('Fred') would be an error? I like that - it 
> means you get an immediate exception if you inadvertently leave out a brace, 
> regardless of whether you leave out the left brace or the right brace.

I kind of like that too, even though } doesn't really have to be quoted.
  It always weird me out that > doesn't have to be quoted in XML.

It occurs to me that the overloading of \ might cause some
complications; % and string.Template use doubling (%% and $$).  For
instance, a little help message:

   write("To include the username ({username}) use \{username\}\n"
         "and use \\\{ and \\\} to include literal
brackets".format(username=u))

Which I isn't all that bad.  I assume other \ sequences won't be
interpretted.  I.e., "\\n".format() produces "\\n".  But I then don't
see any way to do "\\%s" % var.


>>  The format() method does not attempt to interpret the
>> conversion specifiers in any way; it merely passes all of the characters
>> between the first colon ':' and the matching right brace ('}') to the
>> various underlying formatters (described later.)
> 
> If we had a subclassing API similar to what I suggest above, a custom 
> formatter could easily support Ian's pipelining idea by doing:
> 
>    def format_value(self, value, fmt_spec):
>        if fmt_spec is None:
>            val = Formatter.format_value(self, value, fmt_spec)
>        else:
>            for fmt in fmt_spec.split(':'):
>                val = Formatter.format_value(self, value, fmt_spec)
>        return val
> 
> I don't really think that should be the default, though.

It won't work if the __format__ conventions don't support it; if all
objects return strings then pipelining will become much less useful.


> [...]
>> - The trailing letter is optional - you don't need to say '2.2d', you can
>> instead just say '2.2'. If the letter is omitted, then the value will be
>> converted into its 'natural' form (that is, the form that it take if str()
>> or unicode() were called on it) subject to the field length and precision
>> specifiers (if supplied.)
> 
> I disagree with this. These format specifier do a type coercion before 
> applying the formatting. These specifiers should be retained and should 
> continue to result in coercion to int or float or str, with the relevant 
> TypeErrors when that coercion isn't possible.

-1.  I think %d is silly in Python, and we shouldn't replicate that here.


>> 2) Otherwise, see if the value to be formatted has a __format__ method.  If
>> it does, then call it.
> 
> So an object can override standard parsing like {0:d} to return something 
> other than an integer? *shudder*

"{0:d}" doesn't scream "integer" to me.  %d does because of history, but
only because of history.

> Being able to add extra formatting codes for different object types sounds 
> good, but being able to change the meaning of the standard codes sounds (very) 
> bad.

There are no standard codes.  There's standard % codes, but this isn't %.


> If supporting the former also means supporting the latter, then I'd prefer to 
> leave this ability to custom formatter objects or explicit method or function 
> invocations on arguments in the call to format().
> 
>> 3) Otherwise, check the internal formatter within string.format that
>> contains knowledge of certain builtin types.
> 
> This should happen *before* checking for a custom __format__ method. (If we 
> decide to check for a custom __format__ method at all)

How would this change anything?  Presumably only the immutable types
(int, str, list, etc) would be specially handled anyway.


> [...]
>> One other thing that could be done to make the debugging case more
>> convenient would be to allow the locals() dict to be omitted entirely.
>> Thus, a format function with no arguments would instead use the current
>> scope as a dictionary argument:
>>
>> print "Error in file {p.file}, line {p.line}".format()
> 
> Again, I don't think this is worth the additional complexity.

I don't really understand the complexity argument; I think you should be 
more specific about what becomes more complex.

> [...]
>> Other, more radical proposals include backquoting (`), or a new string
>> prefix character (let's say 'f' for 'format'):
>>
>> print f"Error in file {p.file}, line {p.line}"
> 
> A method will do the job with far more flexibility - no need to hack the parser.

In this particular case (where locals() are picked up implicitly) a
method has several flaws.  I don't think the f"" syntax makes any sense
outside of that case; so it's a separate argument (*if* there's support
for a special form evaluated in the scope where the string came from,
then will it use f""?)


-- 
Ian Bicking  |  ianb at colorstudy.com  |  http://blog.ianbicking.org



More information about the Python-3000 mailing list