Search code examples
pythondictionaryintegerstring-formattingunpack

Python: Unpacking dictionary with integer keys?


For a dictionary as follows:

my_dict={'name':'Stack', 'age':11}
print('Name is {name} and age is {age}.'.format(**my_dict))
#output# Name is Stack and age is 11

However, if keys are integers in a dictionary, how should I unpack the dictionary, for example:

new_dict={1:'Stack', 2:'over', 3:'flow'}
print('1 is {1} and 2 is {2} and 3 is {3}'.format(**new_dict))
#output error# tuple index out of range

In this case, how can I get result as follows:

1 is Stack and 2 is over and 3 is flow

I know one can do it with many other ways, but is it possible to use the same strategy in the first example. Thank you.


Solution

  • You can't do that unpacking. What you need is something else.

    ** in a function call unpacks a dict into keyword arguments, and keyword argument names are always strings. An int 1 isn't a valid keyword argument name. Even if it was, or if you converted the dict keys to strings, str.format wouldn't look for such a keyword argument.

    {1}, {2}, etc. in format look for positional arguments, not keyword arguments. No ** unpacking will produce positional arguments. Also, since they're positional, if you start at 1, you would need to have a dummy argument in position 0 so the rest of the arguments can go in the right positions.

    If you really want to do this with a dict and a format string that looks like that, probably the easiest route would be to go through a string.Formatter subclass and override get_value:

    import string
    
    class IntDictFormatter(string.Formatter):
        def get_value(self, key, args, kwargs):
            return kwargs[key]
    
    format_string = '1 is {1} and 2 is {2} and 3 is {3}'
    
    value_dict = {1:'Stack', 2:'over', 3:'flow'}
    
    print(IntDictFormatter().vformat(format_string, (), value_dict))