String Formatting in Python - The Definite Guide
Learn different ways to format strings in Python and test for the fastest method.

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
- String Formatting using the % operator
- Python string format() method
- Python String Template Class
- f-strings
- 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:
- substitute(mapping, **kwds)
This method performs substitutions using dictionary-like key-value-based mapping objects. If keys are missing, it returns a KeyError. - safe_substitute(mapping, **kwds)
Similar behavior as above, but it doesn't throw aKeyError
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.
- If a key is missing from your dictionary-like object, it will throw a
KeyError
. - Any other appearance of
$
in the string will result in aValueError
.
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:-
KeyError
- Use safe_substitute() methodValueError
- 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.

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}")