[Python-Dev] summary of transitioning from % to {} formatting (original) (raw)

Steven D'Aprano steve at pearwood.info
Sat Oct 3 20:01:56 CEST 2009


On Sun, 4 Oct 2009 01:41:36 am Steven Bethard wrote:

I thought it might be useful for those who don't have time to read a million posts to have a summary of what's happened in the formatting discussion.

The basic problem is that many APIs in the standard library and elsewhere support only %-formatting and not {}-formatting, e.g. logging.Formatter accepts:: logging.Formatter(fmt="%(asctime)s - %(name)s") but not:: logging.Formatter(fmt="{asctime} - {name}")

Why is this a problem? Is it because the APIs require extra functionality that only {} formatting can provide? Possibly, but I doubt it -- I expect that the reason is:

(1) Some people would like to deprecate % formatting, and they can't while the std lib uses % internally.

(2) Some APIs in the std lib are tightly coupled to their internal implementation, and so you can't change their implementation without changing the API as well.

Remove either of these issues, and the problem becomes a non-problem, and no action is needed. Personally, I'd like to see no further talk about deprecating % until at least Python 3.2, that is, the earliest we would need to solve this issue would be 3.3. As the Zen says, "Although never is often better than right now."

There seems to be mostly agreement that these APIs should at least support both formatting styles, and a sizable group (including Guido) believe that %-formatting should eventually be phased out (e.g. by Python 4).

-1 on that. Time will tell if I change my mind in a couple of years, but I suspect not -- for simple formatting, I far prefer %. Judging by the reaction on comp.lang.python when this has been discussed in the past, I think a large (or at least loud) proportion of Python programmers agree with me.

There are a number of competing proposals on how to allow such APIs to start accepting {}-format strings:

* Add a parameter which declares the type of format string:: logging.Formatter(fmt="{asctime} - {name}", format=BRACES) The API code would then switch between %-format and {}-format based on the value of that parameter. If %-formatting is to be deprecated, this could be done by first deprecating format=PERCENTS and requiring format=BRACES, and then changing the default to format=BRACES.

+0.5

* Create string subclasses which convert % use to .format calls:: __ = bracefmt_ logging.Formatter(fmt=("{asctime} - {name}"))_

There are a few problems with this approach:

[...]

* Teach the API to accept callables as well as strings:: logging.Formatter(fmt="{asctime} - {name}".format) The API code would just call the object with .format() style arguments if a callable was given instead of a string.

+0.5

* Create translators between %-format and {}-format:: assert tobraces("%(asctime)s") == "{asctime}" assert topercents("{asctime}") == "%(asctime)s"

+1, assuming such translators are even possible. Being optimistic, such translators would have one additional benefit: they would enable modules to completely decouple the API they offer from their internal implementation, without paying a runtime cost on every call, just a single once-off translation at initialisation time.

In theory, this could mean that modules could, if they choose, continue to offer an API based on % long after str.mod is removed from the language.

-- Steven D'Aprano



More information about the Python-Dev mailing list