Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python string format() with dict with integer keys [duplicate]

I would like to use Python string's format() to act as a quick and dirty template. However, the dict that I would like to use has keys which are (string representations) of integers. a simplified example follows:

s = 'hello there {5}'
d = {'5': 'you'}
s.format(**d)

the above code throws the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: tuple index out of range

is it possible to do the above?

like image 816
yee379 Avatar asked Dec 19 '13 09:12

yee379


People also ask

What does dict keys () do in Python?

Python Dictionary keys() The keys() method extracts the keys of the dictionary and returns the list of keys as a view object.

Can dict keys be integers?

Second, a dictionary key must be of a type that is immutable. For example, you can use an integer, float, string, or Boolean as a dictionary key. However, neither a list nor another dictionary can serve as a dictionary key, because lists and dictionaries are mutable.

Do dict Keys return same order?

No, there is no guaranteed order for the list of keys returned by the keys() function. In most cases, the key list is returned in the same order as the insertion, however, that behavior is NOT guaranteed and should not be depended on by your program.


2 Answers

We've established that it won't work, but how about a solution:

Although str.format won't work in this case, funnily enough the old % formatting will. This is not recommended, but you did ask for a quick and dirty template.

>>> 'hello there %(5)s' % {'5': 'you'}
'hello there you'

Do note though that this won't work for integer keys.

>>> 'hello there %(5)s' % {5: 'you'}

Traceback (most recent call last):
  File "<pyshell#1>", line 1, in <module>
    'hello there %(5)s' % {5: 'you'}
KeyError: '5'
like image 149
Volatility Avatar answered Nov 03 '22 08:11

Volatility


I love the idea of extending the Formatter so that it allows arbitrary field names (integers, field names with a colon etc). An implementation might look like this:

import string, re

class QuFormatter(string.Formatter):
    def _quote(self, m):
        if not hasattr(self, 'quoted'):
            self.quoted = {}
        key = '__q__' + str(len(self.quoted))
        self.quoted[key] = m.group(2)
        return '{' + m.group(1) + key + m.group(3) + '}'

    def parse(self, format_string):
        return string.Formatter.parse(self,
            re.sub(r'{([^}`]*)`([^}`]*)`([^}]*)}', self._quote, format_string))

    def get_value(self, key, args, kwargs):
        if key.startswith('__q__'):
            key = self.quoted[key]
        return string.Formatter.get_value(self, key, args, kwargs)

Usage:

d = {'5': 'you', '6': 'me', "okay":1, "weird:thing!": 123456}
print QuFormatter().format(
     'hello there {`5`} {`6`:20s}--{okay}--{`weird:thing!`:20,d}', 
     **d)

So fields in backticks are treated literally.

like image 30
georg Avatar answered Nov 03 '22 09:11

georg