[Python-Dev] transitioning from % to {} formatting

Nick Coghlan ncoghlan at gmail.com
Thu Oct 8 13:53:39 CEST 2009

Antoine Pitrou wrote:
> Vinay Sajip <vinay_sajip <at> yahoo.co.uk> writes:
>>>>> "%0#8x" % 0x1234
>> '0x001234'
>>>>> "{0:0>#8x}".format(0x1234)
>> '000x1234'
> Apart from the sheer unreadability of the {}-style format string, the result 
> looks rather unexpected from a human being's point of view.

The percent format string is pretty unreadable too - you're just more
used to it, so it doesn't look as weird :)

Vinay's problem above is due to using the wrong alignment flag: ">",
which says to right align everything, instead of "=", which says to left
align the sign character and the numeric prefix with the fill character
inserted in the middle. In this particular case he could also use the
zero-padding shortcut which leaves out the alignment flag altogether
(and implies a "0=" alignment format).

That is (using 2.6/3.1):

>>> "%#08x" % 0x1234
>>> "%0#8x" % 0x1234
>>> "{0:#08x}".format(0x1234)
>>> "{0:0>#8x}".format(0x1234)
>>> "{0:0=#8x}".format(0x1234)

Adding in the sign bit gives the following translations:

>>> "%+#08x" % 0x1234
>>> "%+0#8x" % 0x1234
>>> "{0:+#08x}".format(0x1234)
>>> "{0:0>+#8x}".format(0x1234)
>>> "{0:0=+#8x}".format(0x1234)

Note that ">" alignment is actually now *broken* on trunk and py3k,
since ">" and "=" are now behaving exactly the same instead of the
former right aligning the entire number including the sign bit and prefix:

>>> "{:0>+8x}".format(0x1234)
>>> "{:0=+8x}".format(0x1234)

(bug assigned to Eric: http://bugs.python.org/issue7081)

Note that, since percent formatting doesn't allow specification of the
fill characters or the field alignment, translations should probably
rely on the simple field width specifier, optionally selecting zero
padding by preceding it with a zero. It should never be necessary to use
the full alignment spec for translated formats.

The other thing to keep in mind is that brace formatting is fussier
about the order of things - items *must* appear in the order they are
listed in PEP 3101 (i.e. if wanting a zero padded field with leading
sign and numeric prefix, you must write "+#0"). Percent format, on the
other hand, allows the "#", "+" and "0" to be placed in any order you
like (although they must appear before the field width definition,
precision specifier and type code).

As far as I can see, that leaves the prefixing of octal numbers ("0o" vs
"0") as the only true incompatibility between percent formatting and
brace formatting, and even for those the incompatibility is limited to
cases where a field width is specified without leading zeroes or a sign
character is specified. In other cases, the translation can just stick a
leading literal "0" in front of the field in the brace formatting string.


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

More information about the Python-Dev mailing list