String Formatting in Python - The Definite Guide

Learn different ways to format strings in Python and test for the fastest method.

String Formatting in Python - The Definite Guide

According to Zen of Python, there should be one obvious way of doing something. However, there are 4 major ways to perform string formatting in Python. They are:-

String formatting methods

  1. String Formatting using the % operator
  2. Python string format() method
  3. Python String Template Class
  4. f-strings
  5. f-strings are fast

String Formatting using the % operator

The % operator allows you to do simple positional formatting very easily.

Code

name = "Pylenin"
print("I am on %s website" % name)

Output

I am on Pylenin website

By using the %s format specifier, you are telling Python, where to substitute the value of the variable name.

You can also use other format specifiers that produce a different output format.

Code

name = "Pylenin"
num = 50
print("I am on %s website. It has %d blogs"% (name, num))

Output

I am on Pylenin website. It has 50 blogs

The order in which you pass the values is very important.

Let’s look at the example.

Code

print("My name is %s. I love %s" % ("Pylenin", "Python"))
print("My name is %s. I love %s" % ("Python", "Pylenin"))

Output

My name is Pylenin. I love Python
My name is Python. I love Pylenin

This feature of the % operator can make your code unmaintainable.

You can avoid this by using variable substitution in your strings.

Code

name = "Pylenin"
language = "Python"

print("My name is %(name)s. I love %(language)s" %{"name":"Pylenin","language":"Python"})

Output

My name is Pylenin. I love Python

Apart from %s and %d, you can also use other format specifiers.

%s - string representation

%d - Integer representation

%f - Floating point representation

%.<number of digits>f - Floating point representation
                        with a fixed amount of digits 
                        to the right of the decimal.

%e - Exponential representation

%x/%X - Integers in hex representation (lowercase/uppercase)

Let’s look at a few examples.

Code

str1 = "Pylenin"
num = 100

# String representation
print("My name is %s"%str1)

# Integer Representation
print("The number is %d"%num)

# Floating Point representation
print("Floating point representation of %s is %f"%(num, num))
print("Floating point representation of %s with precision 2 is %.2f"%(num, num))

# Exponential Representation
print("Exponential representation of %s is %e"%(num, num))
print("Exponential representation of %s with precision 2 is %.2e"%(num, num))

# Hex representation
print("Hex representation of %s is 0x%X"%(num, num))

Output

My name is Pylenin
The number is 100
Floating point representation of 100 is 100.000000
Floating point representation of 100 with precision 2 is 100.00
Exponential representation of 100 is 1.000000e+02
Exponential representation of 100 with precision 2 is 1.00e+02
Hex representation of 100 is 0x64

Python string format() method

The format() method in Python formats the specified value(s) and inserts them inside the string’s replacement fields. It returns the formatted string.

The replacement fields for the values are defined using curly braces {}.

Code

print("My name is {}. I love {}".format("Pylenin", "Python"))

Output

My name is Pylenin. I love Python

How does format() work in Python?

When placeholders {} in the string are empty, Python will replace the values passed through str.format() in order.

Check out the following example.

Code

# Method 1
print("My name is {}. I love {}".format("Pylenin", "Python"))
print("My name is {}. I love {}".format("Python", "Pylenin"))

Output

My name is Pylenin. I love Python
My name is Python. I love Pylenin

Formatters with Positional Arguments

Similar to indexing in strings, the values present inside string.format() method also start with index 0 and increment by 1 with every value. These index numbers can be passed into the curly braces(replacement fields) serving as the placeholders in the original string.

Let’s look at the following example.

Code

print("My name is {0}. I love {1}".format("Pylenin", "Python"))
print("My name is {1}. I love {0}".format("Pylenin", "Python"))

Output

My name is Pylenin. I love Python
My name is Python. I love Pylenin

Beware - If you try to escape the index 0 or start with a different number, Python will throw you an IndexError.

Code

print("My name is {1}. I love {2}".format("Pylenin", "Python"))

Output

Traceback (most recent call last):
  File "some_file_location", line 2, in <module>
    print("My name is {1}. I love {2}".format("Pylenin", "Python"))
IndexError: Replacement index 2 out of range for positional args tuple

It basically means, you are trying to access the 2nd index from the values within the string.format() method and it doesn’t exist.

However, the following example will work.

Code

print("My name is {1}. I love {2}".format("Pylenin", "Python", "Programming"))```

**Output**

```bash
My name is Python. I love Programming

In this case, you have values inside the string.format() method with index from 0 to 2. You are just not using the 0th index in your string.

Formatters with Keyword Arguments

Instead of empty curly braces or curly braces with index, you can also use keyword arguments.

Code

print("My name is {name}. I love {language}"\
      .format(name="Pylenin", language="Python"))

Output

My name is Pylenin. I love Python

Keyword arguments are like keys in a dictionary. Their order doesn’t matter, as they are matched against a name.

Specifying Formatting Type

You can also use a specific format in string formatting in Python.

Let’s look at the below example.

Code

# integer
print("Integer representation of 99 is {:d}".format(99))

# float
print("Float representation of 99 is {:.2f}".format(99))

# binary
print("Binary representation of 99 is {:b}".format(99))

# exponent
print("Exponential representation of 99 is {:.2e}".format(99))

Output

Integer representation of 99 is 99
Float representation of 99 is 99.00
Binary representation of 99 is 1100011
Exponential representation of 99 is 9.90e+01

You can find a list of available formatters here.


Python String Template Class

The String Template class in Python is used to create a template string using a $ sign. These fields can be replaced later on to create a string object.

This class has 2 key methods:

  1. substitute(mapping, **kwds)

    This method performs substitutions using dictionary-like key-value-based mapping objects. If keys are missing, it returns a KeyError.
  2. safe_substitute(mapping, **kwds)

    Similar behavior as above, but it doesn't throw a KeyError if a key is missing. It just returns the placeholder in the result string.

Let’s look at a few examples.

String Template substitute() method

Example 1

Code

from string import Template

t = Template('$name writes blogs on $language')
s = t.substitute(name='Pylenin', language='Python')
print(s)

# dictionary as substitute argument
d = {'name': 'Pylenin', 'language': 'Python'}
s = t.substitute(**d)
print(s)

Output

Pylenin writes blogs on Python
Pylenin writes blogs on Python
Example 2

Code

from string import Template

# Students and their respective heights
Student = [('Lenin', 190), ('Darshana', 180), ('Chinmayee', 150)]

# Create a basic structure
# to print the name and height
t = Template('Hi $name, your height is $height cm')

for i in Student:
    print(t.substitute(name=i[0], height=i[1]))

Output

Hi Lenin, your height is 190 cm
Hi Darshana, your height is 180 cm
Hi Chinmayee, your height is 150 cm

Let’s look at the possible errors in the String Template substitute() method.

  1. If a key is missing from your dictionary-like object, it will throw a KeyError.
  2. Any other appearance of $ in the string will result in a ValueError.
Example 3

Code

from string import Template

t = Template('$name writes blogs on $language')

d = {'name': 'Pylenin'}
s = t.substitute(**d)
print(s)

Output

KeyError: 'language'
Example 4

Code

from string import Template

t = Template('Give $name $100')

s=t.substitute({"name":"Pylenin"})
print(s)

Output

ValueError: Invalid placeholder in string: line 1, col 12

You can get rid of the above 2 errors using the following:-

  1. KeyError - Use safe_substitute() method
  2. ValueError - Use safe_substitute() method or Escape the $ sign using $$.

String Template safe_substitute() method

If placeholders are missing from mapping and kwds, instead of raising a KeyError exception, the original placeholder will appear in the resulting string.

Example 1

Code

from string import Template

t = Template('$name writes blogs on $language')

d = {'name': 'Pylenin'}
s = t.safe_substitute(**d)
print(s)

Output

Pylenin writes blogs on $language

It can also escape any other appearances of the $ sign.

Example 2

Code

from string import Template

t = Template('Give $name $100')

s=t.safe_substitute({"name":"Pylenin"})
print(s)

Output

Give Pylenin $100

Escaping $ sign with $$

Another way to escape any other appearances of the $ sign, is to use $$ sign.

If you use $$, you can safely use the substitute() method.

Example 3

Code

from string import Template

t = Template('Give $name $$100')

s=t.substitute({"name":"Pylenin"})
print(s)

Output

Give Pylenin $100

Python String Formatting using f-strings

F-strings is a string formatting mechanism introduced by PEP 498 for Python versions 3.6 and above.

F-strings use a leading f character preceding the string literal.

Each of the methods suggested above has their advantages, but in addition, have disadvantages that make them cumbersome to use in practice.

PEP 498 proposed to add a new string formatting mechanism: Literal String Interpolation, also called f-strings(because of the leading f character preceding the string literal).

How to create an f-string

To create an f-string, prefix a string with the letter f. It works similarly to str.format().

Code

num1 = 10
num2 = 5
  
# Adding both numbers 
sum = num1 + num2 
  
# printing values 
print(f"Sum of {num1} and {num2} is {sum}") 

Output

Sum of 10 and 5 is 15

Embed Python expressions in f-string

f-strings provide a convenient way to embed python expressions inside string literals for formatting.

Code

num1 = 10
num2 = 5
  
# printing values 
print(f"Sum of {num1} and {num2} is {num1+num2}") 

Output

Sum of 10 and 5 is 15

You can also call Python functions within an f-string.

Code

x = "Pylenin"

print(f"{x.lower()}")

Output

pylenin

You could also work with objects created from classes with f-strings.

Code

class Programmer:
    def __init__(self, name, language):
        self.name = name
        self.language = language

    def __str__(self):
        return f"{self.name} like {self.language}"

new_programmer = Programmer('Pylenin', 'Python')

print(f"{new_programmer}")

Output

Pylenin like Python

Multiline f-strings

You can use multiple lines with f-strings. Just remember to put f in front of every line.

Code

name = "Pylenin"
language="Python"
age = 29

str1 = f"Hello, I am {name}. \n"\
       f"I love {language}. \n"\
       f"I am {age} years old."

print(str1)

Output

Hello, I am Pylenin. 
I love Python. 
I am 29 years old.

f-strings are fast

Since f-strings are evaluated at runtime, they are faster than both % formatting and string.format() method.

You can confirm it by using the timeit module in Python.

Example 1 - timeit with the % operator

from timeit import timeit

str1 = """
name = "Pylenin"
language="Python"
age = 29

str1 = "Hello, I am %s. "\
       "I love %s. "\
       "I am %d years old."%(name, language, age)

print(str1)
"""
print(timeit(str1, number=10000))

The above code took 0.2817505 secs.

Example 2 - timeit with string.format() method

from timeit import timeit

str1 = """
name = "Pylenin"
language="Python"
age = 29

str1 = "Hello, I am {0}. "\
       "I love {1}. "\
       "I am {2} years old.".format(name, language, age)

print(str1)
"""
print(timeit(str1, number=10000))

The above code took 0.3652804 secs.

Example 3 - timeit with String Template Class

from timeit import timeit

str1 = """
from string import Template

name = "Pylenin"
language="Python"
age = 29

str1 = Template("Hello, I am $name. "\
                "I love $language. "\
                "I am $age years old.")

print(str1.substitute(name=name, language=language, age=age))
"""
print(timeit(str1, number=10000))

The above code took 0.1888825 secs.

Example 4 - timeit with f-strings

from timeit import timeit

str1 = """
name = "Pylenin"
language="Python"
age = 29

str1 = f"Hello, I am {name}. "\
       f"I love {language}. "\
       f"I am {age} years old."

print(str1)
"""
print(timeit(str1, number=10000))

With f-strings, the code only took 0.1565294 secs, considerably lesser than any other method.

Comparison of execution times for all String formatting methods in Python

A simple question

Run the following lines of code in your editor and check the output.

Figure out, why are they being printed that way.

print(f"4 divided by 3 is {4/3:0.2f}")
print(f"4 divided by 3 is {4/3:1.2f}")
print(f"4 divided by 3 is {4/3:2.2f}")
print(f"4 divided by 3 is {4/3:3.2f}")
print(f"4 divided by 3 is {4/3:4.2f}")
print(f"4 divided by 3 is {4/3:5.2f}")
print(f"4 divided by 3 is {4/3:6.2f}")
print(f"4 divided by 3 is {4/3:7.2f}")
print(f"4 divided by 3 is {4/3:8.2f}")
print(f"4 divided by 3 is {4/3:9.2f}")
print(f"4 divided by 3 is {4/3:10.2f}")

Subscribe to Pylenin

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe