Some uses for Python's 'named' form of string formatting

May 9, 2014

I expect that every Python programmer is familiar with Python's normal way of formatting strings with % and 'printf' style format specifications. Let's call this normal way of formatting things a 'positional' way, because it's based on the position of the arguments given to be formatted. But as experienced Python programmers know, this is not the only way you can set up your formatting strings; you can also set them up so that they pick out what to format where based on name instead of argument position. Of course to do this you need to somehow attach names to the arguments, which is done by giving % a dictionary instead of its usual tuple.

Here's what this looks like, for people who haven't seen it before:

print "%(fred)d %(barney)d" % {'fred': 1, 'bob': 2, 'barney': 3}

Note that not all keys in the dictionary need to be used in the format string, unlike with positional arguments.

There are two general uses for named string format specifications, both of which usually start in a situation where the format specification itself is variable. The simple and straightforward use is rearranging the order of what gets printed, which can really come in handy for things like translating messages into different languages (this is apparently a sufficiently common need that it got its own feature in Python 3's new string formatting stuff). The more complex use is to print only a subset of information from a larger collection of available information. Effectively this makes '%' string formatting into a little templating system.

My uses of this have tended to be towards full blown templating where the person configuring my program is trusted to write the formatting strings (note that this can at least throw exceptions if they get it wrong). I can see uses for this in simpler setups, for example to log a number of different messages with somewhat different information depending on some combination of things. Rather than write full blown and repetitive code to explicitly emit N variations of the same logging call, you could just select different name-based formatting strings based on the specific circumstances.

(I'll have to remember to experiment with this idea the next time I have this need. It feels like this might be an interesting new approach to deal with the whole issue of verbosity and including or not including certain bits of information and so on, which can otherwise clutter up the code something awful and be annoying to program.)

PS: Python 3's string formatting does this differently. Following my current policy on Python 3 I'm not thinking about it at all.


Comments on this page:

By Dan Astoorian (Dan.Astoorian) at 2014-05-12 14:19:36:

I've also found it handy when I want to include the same parameters multiple times within a string; e.g., this code to produce a Javascript validator:

   """
   function validate(form) {
       newpass = form.newpass.value;
       if (newpass.length < %(min_passlen)d) {
           alert("New password is too short (minimum %(min_passlen)d).");
       } // ...
    }""" % { 'min_passlen' : config.min_passlen }

In general, I find that formatting using a mapping key instead of a sequential parameter list makes things much more readable once you get format strings more than a few lines long anyway.

--Dan

By opk at 2014-05-13 10:22:17:

Basic C printf can also take arguments out of order with a conversion specification such as %2$s. This is a numeric reference rather than named of course. The main use I know of is language translations.

printf from GNU coreutils or bash don't like it but zsh's printf supports it which has some interesting uses combined with the shell printf feature of reusing the format, consuming all the arguments.

Written on 09 May 2014.
« Operating systems cannot be hermetically sealed environments
Why I don't use relational databases in practice »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Fri May 9 23:34:26 2014
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.