How do I format a string using a dictionary in python-3.x?

229,435

Solution 1

Since the question is specific to Python 3, here's using the new f-string syntax, available since Python 3.6:

>>> geopoint = {'latitude':41.123,'longitude':71.091}
>>> print(f'{geopoint["latitude"]} {geopoint["longitude"]}')
41.123 71.091

Note the outer single quotes and inner double quotes (you could also do it the other way around).

Solution 2

Is this good for you?

geopoint = {'latitude':41.123,'longitude':71.091}
print('{latitude} {longitude}'.format(**geopoint))

Solution 3

To unpack a dictionary into keyword arguments, use **. Also,, new-style formatting supports referring to attributes of objects and items of mappings:

'{0[latitude]} {0[longitude]}'.format(geopoint)
'The title is {0.title}s'.format(a) # the a from your first example

Solution 4

As Python 3.0 and 3.1 are EOL'ed and no one uses them, you can and should use str.format_map(mapping) (Python 3.2+):

Similar to str.format(**mapping), except that mapping is used directly and not copied to a dict. This is useful if for example mapping is a dict subclass.

What this means is that you can use for example a defaultdict that would set (and return) a default value for keys that are missing:

>>> from collections import defaultdict
>>> vals = defaultdict(lambda: '<unset>', {'bar': 'baz'})
>>> 'foo is {foo} and bar is {bar}'.format_map(vals)
'foo is <unset> and bar is baz'

Even if the mapping provided is a dict, not a subclass, this would probably still be slightly faster.

The difference is not big though, given

>>> d = dict(foo='x', bar='y', baz='z')

then

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format_map(d)

is about 10 ns (2 %) faster than

>>> 'foo is {foo}, bar is {bar} and baz is {baz}'.format(**d)

on my Python 3.4.3. The difference would probably be larger as more keys are in the dictionary, and


Note that the format language is much more flexible than that though; they can contain indexed expressions, attribute accesses and so on, so you can format a whole object, or 2 of them:

>>> p1 = {'latitude':41.123,'longitude':71.091}
>>> p2 = {'latitude':56.456,'longitude':23.456}
>>> '{0[latitude]} {0[longitude]} - {1[latitude]} {1[longitude]}'.format(p1, p2)
'41.123 71.091 - 56.456 23.456'

Starting from 3.6 you can use the interpolated strings too:

>>> f'lat:{p1["latitude"]} lng:{p1["longitude"]}'
'lat:41.123 lng:71.091'

You just need to remember to use the other quote characters within the nested quotes. Another upside of this approach is that it is much faster than calling a formatting method.

Solution 5

print("{latitude} {longitude}".format(**geopoint))
Share:
229,435

Related videos on Youtube

Doran
Author by

Doran

Updated on June 18, 2021

Comments

  • Doran
    Doran almost 3 years

    I am a big fan of using dictionaries to format strings. It helps me read the string format I am using as well as let me take advantage of existing dictionaries. For example:

    class MyClass:
        def __init__(self):
            self.title = 'Title'
    
    a = MyClass()
    print 'The title is %(title)s' % a.__dict__
    
    path = '/path/to/a/file'
    print 'You put your file here: %(path)s' % locals()
    

    However I cannot figure out the python 3.x syntax for doing the same (or if that is even possible). I would like to do the following

    # Fails, KeyError 'latitude'
    geopoint = {'latitude':41.123,'longitude':71.091}
    print '{latitude} {longitude}'.format(geopoint)
    
    # Succeeds
    print '{latitude} {longitude}'.format(latitude=41.123,longitude=71.091)
    
  • Homunculus Reticulli
    Homunculus Reticulli almost 12 years
    Tried this and it worked. But I don't understand the use of the 'pointer notation'. I know Python doesn't use pointers, is this an example of kwargs?
  • D.Rosado
    D.Rosado almost 12 years
    @HomunculusReticulli That is a format parameter (Minimum field width), not a pointer to a pointer C++ style. docs.python.org/release/2.4.4/lib/typesseq-strings.html
  • diapir
    diapir over 9 years
    Python 3.2 introduced format_map. Similar to str.format(**mapping), except that mapping is used directly and not copied to a dict. This is useful if for example mapping is a dict subclass
  • Bhargav Rao
    Bhargav Rao about 8 years
    Nice one, Is there any performance improvements over format? (Given that it is not copied to a dict)
  • Antti Haapala -- Слава Україні
    Antti Haapala -- Слава Україні about 8 years
    @BhargavRao not much, 2 % :D
  • Løiten
    Løiten over 7 years
    I find this answer better, as adding the positional index for the placeholder makes the code more explicit, and easier to use. Especially if one has something like this: '{0[latitude]} {1[latitude]} {0[longitude]} {1[longitude]}'.format(geopoint0, geopoint1)
  • Whymarrh
    Whymarrh over 7 years
    This is useful if you're using a defaultdict and don't have all the keys
  • Nityesh Agarwal
    Nityesh Agarwal about 7 years
    @eugene What does ** do to a python dictionary? I don't think that it creates an object because print(**geopoint) fails giving syntax error
  • abhisekp
    abhisekp about 7 years
    @NityeshAgarwal it spreads the dictionary with the name=value pairs as individual arguments i.e. print(**geopoint) is same as print(longitude=71.091, latitude=41.123). In many languages, it is known as splat operator. In JavaScript, it's called spread operator. In python, there is no particular name given to this operator.
  • Jonatas CD
    Jonatas CD almost 6 years
    I would say that use of the f-string is more aligned to python3 approach.
  • Samie Bencherif
    Samie Bencherif over 5 years
    @NityeshAgarwal new to me too. it's pretty cool.
  • Hugo
    Hugo over 4 years
    Keep in mind that f-strings are new to Python 3.6, and not in 3.5.
  • Tcll
    Tcll about 4 years
    plus it's also noticably more performant than f"" or "".format() ;)
  • Tcll
    Tcll about 4 years
    you missed one ;) print('%(latitude)s %(longitude)s'%geopoint) this is also significantly faster than the other 2
  • Tcll
    Tcll about 4 years
    note there's a chance 'longitude' could come before 'latitude' from geopoint.items() ;)
  • Tcll
    Tcll about 4 years
    @BhargavRao if you're looking for performance, use this '%(latitude)s %(longitude)s'%geopoint ;)
  • Sheikh Abdul Wahid
    Sheikh Abdul Wahid about 4 years
    @tcll Actually I wanted the examples, where I can use the dictionary name inside the string. Something like this '%(geopoint["latitude"])s %(geopoint["longitude"])s'%{"geopoint":geopoint}
  • JohnMudd
    JohnMudd over 3 years
    Thanks! I don't know why this doesn't have more votes.
  • Aleksandr Panzin
    Aleksandr Panzin about 3 years
    This is the simplest option, TBH. It's also the similar way as you transform a list to varargs. This should be the way.