String formatting with two dictionaries?

Robert Amesz reqhye72zux at
Wed Oct 10 01:44:23 CEST 2001

Xavier Defrang wrote:

> On Tue, 9 Oct 2001, Carsten Gaebler wrote:
>> "%(foo) %(bar)" % magic(dict1, dict2, ...)
> So what about writing a class called "magic" that takes a bunch of
> dictionaries as __init__ arguments, and use an overridden
> __getitem__ to perform look-ups thegiven dictionaries? 

That was my first thought too. Shouldn't be hard to come up with 
something useful:

- - -

class multidict:
    def __init__(self, *dicts):
        self.dicts = dicts

    def __getitem__(self, item):
        for dict in self.dicts:
                return dict[item]
            except KeyError:
        raise KeyError(str(item))

d1 = {"foo": "bar"}
d2 = {"spam": "eggs"}
s = "%(foo)s %(spam)s"
print s % multidict(d1, d2)

- - -

Notice that this isn't a real dictionary: it only has a __getitem__ 
method. Conversely, it only *uses* that method, too. As such, its uses 
are limited, but at a cost of only 12 lines of code that's hardly an 

I once used an even simpler class to return a default value for a 
dictionary, also for string interpolation. (Otherwise I'd have been 
able to use dict.get(key, defaultvalue) directly, of course.)

What I'd like to see for the %(key)s type string interpolation is for 
it to be slightly more forgiving in that the trailing 's' should be 
optional (IMHO, of course). A % without any formatting character could 
mean anything, but after %(key) there can hardly be any doubt that we 
want something inserted at this point, and that 'something' is usually 
a string. Even if it isn't a string, it will be coerced into one, and I 
can't think of any case where this will display something other than 
you'd expect[*]. (Thus, the 'principle of least suprise' is 

I can't think of any code this would break. (It's hard to be certain: 
the ability to catch exceptions could mean that some program actually 
counts on this happening.)

Robert Amesz
[*] Testing a bit further, this isn't strictly true. Using %f will not 
display as many digits as %s, when trying to display 1.0/7, and what's 
even stranger is that the interactive display will show even more 
digits. (A mantissa of 6, 12 and 17 digits, respectively.) It's a 
curious, if minor inconsistency.

More information about the Python-list mailing list