skip to content
Jakub Szafran

Python: str.format and str.format_map differences

/ 2 min read

I’ve recently stumbled upon str.format_map method in Python and this short article describes how it works and how it differs from str.format.

format method

format string method allows for substituting placeholders (constructed by using {}) within string with the values provided by the caller, i.e.:

>>> tmpl1 = "first_name: {} | last_name: {}"
>>> tmpl1.format("John", "Doe")
'first_name: John | last_name: Doe'

Bare {} placeholders will be substituted with positional arguments passed to format method.

You could also add numbers to placeholders and they’ll be used for accessing positional arguments by index. This also lets you use one value in multiple place of the template (without repeating it as an argument):

>>> tmpl2 = "first_name: {0} | last_name: {1}"
>>> tmpl2.format("John", "Doe")
'first_name: John | last_name: Doe'

>>> tmpl3 = "first_name: {0} | last_name: {1} | last_name: {1}"
>>> tmpl3.format("John", "Doe")
'first_name: John | last_name: Doe | last_name: Doe'

You can also “name” your placeholders and keywords arguments/unpacked dictionary for passing substitution values:

>>> tmpl4 = "first_name: {first_name} | last_name: {last_name}"
>>> tmpl4.format(first_name="John", last_name="Doe")
'first_name: John | last_name: Doe'

>>> tmpl4.format(**{"first_name": "John", "last_name": "Doe"})
'first_name: John | last_name: Doe'

When supplying a dictionary, it must contain all keys from the template. Otherwise, KeyError is thrown:

>>> tmpl4.format(**{"first_name": "John"})
KeyError: 'last_name'

format_map and how it’s different from format?

Similarly to format method, format_map allows for substitution of placeholders in the string with given values. formap_map accepts a single argument (mapping):

>>> tmpl4.format_map({"first_name": "John", "last_name": "Doe"})
'first_name: John | last_name: Doe'

The difference between

tmpl4.format(**{"first_name": "John", "last_name": "Doe"})


tmpl4.format_map({"first_name": "John", "last_name": "Doe"})

is that format(**some_dict) operates on a copy of dictionary while format_map(some_dict) does not create a new copy of some_dict dictionary.

The other difference in their behaviours is that format_map works with subclasses of dict class. It allows for customizing the behaviour of missing key - by implementing __missing__ dunder method.

Let’s create such class:

class Person(dict):

    def __missing__(self, key):
        return "N/A"

>>> p1 = Person(first_name="John")
>>> p1["first_name"]
>>> p1["last_name"]

>>> tmpl4.format_map(p1)
'first_name: John | last_name: N/A'

Even though p1 object was not initialized with last_name value, format_map did not raise any error and used the result of custom missing key behaviour when substituting value for {last_name} placeholder.

(3/52) This is a 3rd post for my blogging challenge (publishing 52 posts in 2024).