[Python-Dev] transitioning from % to {} formatting
Steven D'Aprano
steve at pearwood.info
Wed Sep 30 16:34:27 CEST 2009
On Wed, 30 Sep 2009 03:04:05 pm James Y Knight wrote:
> It'd possibly be helpful if there were builtin objects which forced
> the format style to be either newstyle or oldstyle, independent of
> whether % or format was called on it.
>
> E.g.
> x = newstyle_formatstr("{} {} {}")
> x % (1,2,3) == x.format(1,2,3) == "1 2 3"
People will want this formatstr object to behave like strings, with
concatenation, slicing, etc.:
>>> x = newstyle_formatstr("x{} {} : ")
>>> y = newstyle_formatstr("{}")
>>> (x[1:] + y) % (1, 2, 3)
'1 2 : 3'
Instead of having to support one type with %-formatting and
{}-formatting (str), now the std lib will have two classes
with %-formatting and {}-formatting. How is this an improvement?
Moving along, let's suppose the newstyle_formatstr is introduced. What's
the intention then? Do we go through the std lib and replace every call
to (say)
somestring % args
with
newstyle_formatstr(somestring) % args
instead? That seems terribly pointless to me -- it does nothing about
getting rid of % but adds a layer of indirection which slows down the
code. Things are no better if the replacement code is:
newstyle_formatstr(somestring).format(*args)
(or similar). If we can do that, then why not just go all the way and
use this as the replacement instead?
somestring.format(*args)
> and perhaps, for symmetry:
> y = oldstyle_formatstr("%s %s %s")
> y.format(1,2,3) == x % (1,2,3) == "1 2 3"
Now we have three classes that support both % and {} formatting. Great.
[...]
> This could allow for a controlled switch towards the new format
> string format, with a long deprecation period for users to migrate:
>
> 1) introduce the above feature, and recommend in docs that people
> only ever use new-style format strings, wrapping the string in
> newstyle_formatstr() when necessary for passing to an API which uses
> % internally.
And how are people supposed to know what the API uses internally?
Personally, I think your chances of getting people to write:
logging.Formatter(newstyle_formatstr("%(asctime)s - %(name)s - %(level)s - %(msg)s"))
instead of
logging.Formatter("%(asctime)s - %(name)s - %(level)s - %(msg)s")
is slim to none -- especially when the second call still works. You'd
better off putting the call to newstyle_formatstr() inside
logging.Formatter, and not even telling the users.
Instead of wrapping strings in a class that makes .__mod__()
and .format() behave the same, at some cost on every call presumably,
my preferred approach would be a converter function (perhaps taken from
2to3?) which modified strings like "%(asctime)s" to "{asctime}". That
cost gets paid *once*, rather than on every call.
(Obviously the details will need to be ironed out, and it will depend on
the external API. If the external API depends on the caller using %
explicitly, then this approach may not work.)
> 2) A long time later...deprecate str.__mod__;
How long? I hope that's not until I'm dead and buried.
--
Steven D'Aprano
More information about the Python-Dev
mailing list