[Python-ideas] One way to do format and print

Nick Coghlan ncoghlan at gmail.com
Tue Sep 8 02:31:56 CEST 2015

On 8 September 2015 at 09:28, Random832 <random832 at fastmail.com> wrote:
> Ryan Gonzalez <rymg19 at gmail.com> writes:
>> t = (1, 2, 3)
>> # 400 lines later...
>> print '%s' % t # oops!
> I always use % (t,) when intending to format a single object. But
> anyway, my ideal version of it would have a .format method, but using
> identical format strings. My real question was what the benefit of the
> {}-format for format strings is, over an extended %-format.

It turns out PEP 3101 doesn't really go into this, so I guess it was a
case where all of us involved in the discussion knew the reasons a new
format was needed, so we never wrote them down.

As such, it's worth breaking the problem down into a few different subproblems:

1. Invocation via __mod__
2. Positional formatting
3. Name based formatting
4. Extending formatting to new types in an extensible, backwards compatible way

The problems with formatting dictionaries and tuples relate to the
"fmt % values" invocation model, rather than the substitution field
syntax. As such, we *could* have designed str.format() and
str.format_map() around %-interpolation. The reasons we chose not to
do that relate to the other problems.

For positional formatting of short strings, %-interpolation actually
works pretty well, and it has the advantage of being consistent with
printf() style APIs in C and C++. This is the use case where it has
proven most difficult to get people to switch away from
mod-formatting, and is also the approach we used to restore binary
interpolation support in Python 3.5. An illustrative example is to
compare formatting a floating point number to use 2 decimal places:

    >>> x = y = 1.0
    >>> "%.2f, %.2f" % (x, y)
    '1.00, 1.00'
    >>> "{:.2f}, {:.2f}".format(x, y)
    '1.00, 1.00'

I consider the second example there to be *less* readable than the
original mod-formatting. These kinds of cases are why we *changed our
mind* from "we'd like to deprecate mod-formatting, but we haven't
figured out a practical way to do so" to "mod-formatting and
brace-formatting are better at different things, so it's actually
useful having both of them available".

For name based formatting, by contrast, the "%(name)s" syntax is noisy
and clumsy compared to the shorter "{name}" format introduced in PEP
3101 (borrowed from C#). There the value has been clear, and so folks
have been significantly more amenable to switching away from

    >>> "%(x).2f, %(y).2f" % dict(x=x, y=y)
    '1.00, 1.00'
    >>> "{x:.2f}, {y:.2f}".format(x=x, y=y)
    '1.00, 1.00'

It's that last example which PEP 498 grants native syntax, with the
entire trailing method call being replaced by a simple leading "f":

    >>> f"{x:.2f}, {y:.2f}"
    '1.00, 1.00'

This gets us back to TOOWTDI (after a long detour away from it), since
direct interpolation will clearly be the obvious way to go when
interpolating into a literal format string - the other options will
only be needed when literal formatting isn't appropriate for some

The final reason for introducing a distinct formatting system doesn't
relate to syntax, but rather to semantics. Mod-formatting is defined
around the builtin types, with "__str__" as the catch-all fallback for
interpolating arbitrary objects. PEP 3101 introduced a new *protocol*
method (__format__) that allowed classes more control over how their
instances were formatted, with the typical example being to allow
dates and times to accept strftime formatting strings directly rather
than having to make a separate strftime call prior to formatting.
Python generally follows a philosophy of "constructs with different
semantics should use different syntax" (at least in the core language
design), which is reflected in the fact that a new formatting syntax
was introduced in conjunction with a new formatting protocol.


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list