String interpolation allows you to create strings by inserting objects into specific places in a target string template. Python has several tools for string interpolation, including f-strings, the str.format()
method, and the modulo operator (%
). Python’s string
module also provides the Template
class, which you can use for string interpolation.
In this tutorial, you’ll:
- Learn how to use f-strings for eager string interpolation
- Perform lazy string interpolation using the
str.format()
method - Learn the basics of using the modulo operator (
%
) for string interpolation - Decide whether to use f-strings or the
str.format()
method for interpolation - Create templates for string interpolation with
string.Template
To get the most out of this tutorial, you should be familiar with Python strings, which are represented by the str
class.
Get Your Code: Click here to download the free sample code you’ll use to explore string interpolation tools in Python.
Take the Quiz: Test your knowledge with our interactive “String Interpolation in Python: Exploring Available Tools” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
String Interpolation in Python: Exploring Available ToolsTake this quiz to test your understanding of the available tools for string interpolation in Python, as well as their strengths and weaknesses. These tools include f-strings, the .format() method, and the modulo operator.
String Interpolation in Python
Sometimes, when working with strings, you’d make up strings by using multiple different string values. Initially, you could use the plus operator (+
) to concatenate strings in Python. However, this approach results in code with many quotes and pluses:
>>> name = "Pythonista"
>>> day = "Friday" # Of course 😃
>>> "Hello, " + name + "! Today is " + day + "."
'Hello, Pythonista! Today is Friday.'
In this example, you build a string using some text and a couple of variables that hold string values. The many plus signs make the code hard to read and write. Python must have a better and cleaner way.
Note: To learn more about string concatenation in Python, check out the Efficient String Concatenation in Python tutorial.
The modulo operator (%
) came to make the syntax a bit better:
>>> "Hello, %s! Today is %s." % (name, day)
'Hello, Pythonista! Today is Friday.'
In this example, you use the modulo operator to insert the name
and day
variables into the string literals. The process of creating strings by inserting other strings into them, as you did here, is known as string interpolation.
Note: Formatting with the modulo operator is inspired by printf()
formatting used in C and many other programming languages.
The %s
combination of characters is known as a conversion specifier. They work as replacement fields. The %
operator marks the start of the specifier, while the s
letter is the conversion type and tells the operator that you want to convert the input object into a string. You’ll learn more about conversion specifiers in the section about the modulo operator.
Note: In this tutorial, you’ll learn about two different types of string interpolation:
- Eager interpolation
- Lazy interpolation
In eager interpolation, Python inserts the values into the string at execution time in the same place where you define the string. In lazy interpolation, Python delays the insertion until the string is actually needed. In this latter case, you create string templates at one point in your code and fill the template with values at another point.
But the story doesn’t end with the modulo operator. Later, Python introduced the str.format()
method:
>>> "Hello, {}! Today is {}.".format(name, day)
'Hello, Pythonista! Today is Friday.'
The method interpolates its arguments into the target string using replacement fields limited by curly brackets. Even though this method can produce hard-to-read code, it represents a significant advance over the modulo operator: it supports the string formatting mini-language.
Note: String formatting is a fundamental topic in Python, and sometimes, people think that formatting and interpolation are the same. However, they’re not. In this tutorial, you’ll only learn about interpolation. To learn about string formatting and the formatting mini-language, check out the Python’s Format Mini-Language for Tidy Strings tutorial.
Python continues to evolve, and every new version brings new, exciting features. Python 3.6 introduced formatted string literals, or f-strings for short:
>>> f"Hello, {name}! Today is {day}."
'Hello, Pythonista! Today is Friday.'
F-strings offer a more readable and clean way to create strings that include other strings. To make an f-string, you must prefix it with an f
or F
. Again, curly brackets delimit the replacement fields.
Note: To learn more about f-strings, check out the Python’s F-String for String Interpolation and Formatting tutorial.
F-strings are probably the most popular interpolation tool nowadays in Python. They’re readable, quick to write, and efficient. So, you’ll start with f-strings and how to use them to build new strings using interpolation.
Using F-String Literals to Build Strings
For most interpolation use cases, f-strings are probably the best choice if you’re using Python 3.6 or greater. Their syntax is readable and concise. Additionally, they’ll run faster than other tools.
One use case where f-strings aren’t the way to go is when you need to do lazy interpolation. In other words, when you need to create a string template and insert the components later depending on the code’s execution. In this case, Python takes the lazy option and delays working out the value returned by an expression until that value is needed.
Another consideration to keep in mind is security. Because f-strings evaluate at runtime, they could potentially expose your application to code injection attacks if you don’t carefully sanitize users’ input before interpolatation.
In the following sections, you’ll learn how to use f-strings for eager string interpolation in Python.
Interpolating Values in F-Strings
Using f-strings, you can interpolate variables and expressions directly into your strings. Then, when Python executes the f-string, the variable’s content or the expression’s result will be interpolated into the f-string literal to build the final string:
>>> x = 5
>>> y = 10
>>> f"The sum of {x} and {y} is {x + y}."
'The sum of 5 and 10 is 15.'
In this example, you have two variables, x
and y
. Then, you create an f-string literal with three replacement fields. The first two fields hold the variables, and the third field holds an expression.
It’s important to note that Python evaluates f-strings at runtime. So, in this example, x
, y
, and x + y
are evaluated and interpolated into the string literal when Python runs the line of code containing the f-string.
You can embed almost any Python expression in an f-string, such as arithmetic, comparison, and Boolean expressions. You can also use functions and method calls, and even comprehensions or other more complex expressions:
>>> import math
>>> radius = 16
>>> f"The area of your circle is {math.pi * radius ** 2}"
'The area of your circle is 804.247719318987'
>>> name = "Pythonista"
>>> site = "real python"
>>> f"Hello, {name.upper()}! Welcome to {site.title()}!"
'Hello, PYTHONISTA! Welcome to Real Python!'
>>> f"{[2**n for n in range(3, 9)]}"
'[8, 16, 32, 64, 128, 256]'
In the first f-string, you embed a math expression into the replacement field. In the second example, you use the .upper()
and .title()
string methods in the replacement fields. Python evaluates the expression and calls the method for you. Then, it inserts the results into the resulting f-string literal. In the final example, you create an f-string that embeds a list comprehension. The comprehension creates a new list of powers of 2
.
Note: Python’s f-strings convert the interpolated values into strings by default:
>>> f"The number is {42}"
'The number is 42'
>>> f"Pi {3.14}"
'Pi 3.14'
In these examples, you interpolate numeric values into your f-string. Python converts them into string objects while performing the interpolation.
F-strings before Python 3.12 have a few limitations that you must consider when working with them. Inside the replacement fields, you can’t:
- Reuse quotes or string delimiters
- Embed backslashes, which means you can’t use escape sequences
- Add inline comments
- Nest f-strings beyond the available quoting variations
PEP 536 lists all these limitations. To see them in action, check out the F-Strings Had Some Limitations Before Python 3.12 section in the Python 3.12 Preview tutorial.
Self-Documenting the Interpolated Value
With f-strings, you can use a feature known as self-documenting expressions that adds an equal sign after the interpolated variable or expression. This feature can help you debug your code. For quick debugging, most people use the built-in print()
function to check the value of a variable or the result of an expression:
>>> value = "Suspicious value"
>>> print(f"{value = }")
variable = 'Suspicious value'
>>> f"{2 + 3 = }"
'2 + 3 = 5'
You can use a variable or an expression followed by an equal sign (=
) in an f-string to create a self-documenting expression. When Python runs the f-string, it builds an expression-like string containing the variable or expression, the equal sign, and the current result.
In these examples, the whitespaces around the equal sign aren’t required, but they make the output more readable.
The self-documenting expressions feature adds readability to your string interpolation process and can be an excellent tool for quick debugging with print()
.
Using Different String Representations in F-Strings
F-strings allow you to use two flags with special meaning in the interpolation process. These flags relate to how Python deals with an object’s string representation. Here are the flags and their intended meaning:
Flag | Description |
---|---|
!s |
Interpolates the string representation using .__str__() |
!r |
Interpolates the string representation using .__repr__() |
Ideally, the .__str__()
special method should provide a user-friendly string representation of an object. Python falls back to calling this method when you use the str()
function. Meanwhile, the .__repr__()
method returns a developer-friendly representation, which you get when you use the repr()
function.
Note: The !s
flag is the default behavior in f-strings, so you’ll rarely need to explicitly use it.
To illustrate how these flags work, consider the following sample class:
article.py
class Article:
def __init__(self, title, author, pub_date):
self.title = title
self.author = author
self.pub_date = pub_date
def __str__(self):
return (
f"Article: {self.title}\n"
f"Author: {self.author}\n"
f"Published: {self.pub_date}\n"
)
def __repr__(self):
return (
f"{type(self).__name__}("
f"title={self.title!r}, "
f"author={self.author!r}, "
f"pub_date={self.pub_date!r})"
)
This Article
class has three instance attributes .title
, .author
, and .pub_date
. The .__str__()
method returns a string containing the article’s information in a user-friendly format. This message is targeted to end users rather than developers.
Note: To dive deeper into the .__str__()
and .__repr__()
methods, check out When Should You Use. .__repr__()
vs .__str__()
in Python?
The .__repr__()
method returns a string that’s a developer-friendly representation of the object. In short, the representation tells the developer how the current instance was created. Ideally, the developer should be able to copy this string representation and create an equivalent object.
Now your class is ready for the !s
and !r
flags:
>>> from article import Article
>>> article = Article(
... title="String Interpolation in Python: Exploring Available Tools",
... author="Real Python",
... pub_date="2024-06-03",
... )
>>> print(f"{article!s}")
Article: String Interpolation in Python: Exploring Available Tools
Author: Real Python
Published: 2024-06-03
>>> print(f"{article!r}")
Article(
title='String Interpolation in Python: Exploring Available Tools',
author='Real Python',
pub_date='2024-06-03'
)
In the first f-string, you use the !s
tag to interpolate the string representation that .__str__()
returns. In the second f-string, you use the !r
flag to interpolate the developer-friendly string representation of your object. Notice that, in the latter case, the resulting string object represents a valid Python code that you can evaluate.
Creating Strings With the str.format()
Method
If you need to interpolate values into strings lazily, then the str.format()
method is for you. This method is a versatile tool for string interpolation in Python. It provides a readable syntax and allows for both eager and lazy interpolation.
Note: Remember that eager interpolation is done at execution time, and lazy interpolation is when you create a string template and defer the interpolation of values to a later time.
In the following sections, you’ll learn how to use the .format()
method for lazy interpolation because, in most cases, you’d use f-strings for eager interpolation.
Using Positional and Named Arguments
To interpolate objects into a string using the .format()
method, you can use three different approaches. You can use:
- Empty replacement fields,
{}
- Replacement fields with zero-based indices,
{0} ... {n}
- Replacement fields with named arguments,
{arg_1} ... {arg_n}
To illustrate how these options work, say that you need to automate the process of generating emails for the customers who purchase products from your company. You can create an email template and then interpolate the customer data dynamically:
>>> template = """
... Dear {},
...
... Thank you for your recent purchase of {}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {}
... """
>>> print(template.format("Emily", "MacBook Pro 16-inch", "John"))
Dear Emily,
Thank you for your recent purchase of MacBook Pro 16-inch.
Remember, our support team is always here to assist you.
Best regards,
John
In this example, you create an email template with three empty replacement fields. The .format()
method inserts the passed values in the appropriate field using their relative position. If you want to have a bit more control over how the values are interpolated, then you can use integer indices:
>>> template = """
... Dear {0},
...
... Thank you for your recent purchase of {1}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {2}
... """
>>> print(template.format("Linda", "Samsung Galaxy S22", "Jane"))
Dear Linda,
Thank you for your recent purchase of Samsung Galaxy S22.
Remember, our support team is always here to assist you.
Best regards,
Jane
In this example, the result is similar. However, now you’re certain that the first argument, "Linda"
, will go to index 0
, the second argument, "Samsung Galaxy S22"
will go to index 1
, and so on. This way of handling the arguments can be useful when the arguments’ original order isn’t the same as the order in the final string:
>>> template = """
... Dear {1},
...
... Thank you for your recent purchase of {0}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {2}
... """
>>> purchase = ("Samsung Galaxy S22", "Linda", "Jane")
>>> print(template.format(*purchase))
Dear Linda,
Thank you for your recent purchase of Samsung Galaxy S22.
Remember, our support team is always here to assist you.
Best regards,
Jane
Here, the order of the items in the purchase
tuple doesn’t match the natural order in the template. So, you move the indices according to the new order and get the desired result.
Note: You can also repeat arguments’ indices in a string template. Consider the following toy example:
>>> prefix = "re"
>>> template = "{0}-create and {0}start"
>>> template.format(prefix)
're-create and restart'
In this example, you use the prefix
variable as an argument to .format()
. By inserting the 0
index twice in the template, you get prefix
inserted twice as well.
Even though the above options work okay, they aren’t completely readable. Fortunately, there’s a better way. You can use keyword arguments with .format()
. Here’s how:
>>> template = """
... Dear {customer},
...
... Thank you for your recent purchase of {product}.
...
... Remember, our support team is always here to assist you.
...
... Best regards,
... {employee}
... """
>>> print(
... template.format(
... customer="Bob",
... product="Canon EOS R5",
... employee="Kate"
... )
... )
Dear Bob,
Thank you for your recent purchase of Canon EOS R5.
Remember, our support team is always here to assist you.
Best regards,
Kate
In this update, you’ve used explicit names in the replacement fields. These names match the keyword arguments you used when calling .format()
. Your code now looks much more readable.
Finally, it’s also possible to use dictionaries to feed the .format()
method. Say that you’re retrieving your data from a CSV file that looks something like this:
sales.csv
product,customer,employee
MacBook Pro 16-inch,Emily,John
Samsung Galaxy S22,Linda,Jane
Canon EOS R5,Bob,Kate
You can use the csv
module from the standard library to process this file and load its content so that you can create emails for each sale. The csv.DictReader
is a good tool for this task. This reader allows you to read every line in a CSV file into a dictionary. The keys will be the file headings, and the values will be the values in each row.
Here’s the code that you can use to do the job:
emails.py
import csv
template = """
Dear {customer},
Thank you for your recent purchase of {product}.
Remember, our support team is always here to assist you.
Best regards,
{employee}
"""
def display_emails(template, path):
with open(path) as file:
for customer in csv.DictReader(file):
print(template.format(**customer))
display_emails(template, "sales.csv")
In this code, you first import csv
from the standard library. Then, you have the usual email template with names in the replacement fields. The names match the headings in the CSV file.
Next, you have the display_emails()
function. This function takes two arguments: the email template and the path to the CSV file. Inside the function, you open the input file for reading using a with
statement.
The for
loop iterates over the lines of the file using the DictReader
class. Finally, you use the .format()
method to interpolate the values in the current line into the email template. In this example, you use the dictionary unpacking operator (**
) to provide the arguments to .format()
.
Go ahead and run this script from your command line to check the output.
There’s another interesting behavior of .format()
when you use it with dictionaries. Here’s a quick toy example:
>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> "{one}-{two}".format(**numbers)
'1-2'
>>> "{one}-{two}-{three}".format(**numbers)
'1-2-3'
>>> "{one}-{two}-{three}-{four}".format(**numbers)
Traceback (most recent call last):
...
KeyError: 'four'
When the keys in the input dictionary match the named arguments in the string, the interpolation works even if you have unused keys. When the keys don’t match the named arguments, then you get a KeyError
exception.
Using Different String Representations With .format()
Like with f-strings, you can also use the !s
and !r
flags with .format()
to insert objects into your strings using different string representations. Reusing the Article
class from the Using Different String Representations in F-Strings section, here are two examples that show how the flags work:
>>> from article import Article
>>> article = Article(
... title="String Interpolation in Python: Exploring Available Tools",
... author="Real Python",
... pub_date="2024-06-03",
... )
>>> print("{article!s}".format(article=article))
Article: String Interpolation in Python: Exploring Available Tools
Author: Real Python
Published: 2024-06-03
>>> print("{article!r}".format(article=article))
Article(
title='String Interpolation in Python: Exploring Available Tools',
author='Real Python',
pub_date='2024-06-03'
)
Again, the !s
flag allows you to use the user-friendly string representation of the object at hand. In contrast, the !r
flag allows you to use the developer-friendly representation. You’ll decide which flag to use in your code by considering the target audience of your code.
Using the Modulo Operator (%
) for Interpolation
Using the modulo operator (%
) for string interpolation is largely obsolete in modern Python. However, this tool still works, and you’ll probably find legacy code that uses it. So, it’s good to know how it works.
Note: In modern Python, you’ll often see f-strings used and find yourself using them for string interpolation. This is because f-strings are readable, clean, and fast. However, there are better solutions for some use cases. Sometimes, you need to perform lazy interpolation, in which case, the recommended tool is the .format()
method. So, you likely end up completely ignoring the modulo operator in string interpolation.
The modulo operator (%
) is the oldest tool for performing string interpolation in Python. Even though you can use this operator for both eager and lazy string interpolation, the syntax could be more readable and clean.
You need to insert conversion specifiers into your strings and then use the modulo operator to interpolate the desired values:
>>> x = 5
>>> y = 10
>>> "The sum of %d and %d is %d." % (x, y, x + y)
'The sum of 5 and 10 is 15.'
A combination of characters starting with the percent sign (%
) is known as a conversion specifier. In this example, you’ve used the %d
specifier, which means that you want to convert a signed integer decimal value into a string. The conversion specifiers work as replacement fields for the modulo operator.
Note: The modulo operator is the only interpolation tool that allows you to interpolate values into bytes
objects:
>>> name = b"Pythonista"
>>> b"Hello, %b!" % name
b'Hello, Pythonista!'
You can’t do this type of interpolation using f-strings because the fb""
or bf""
syntax isn’t valid. The .format()
method doesn’t allow for this type of interpolation because bytes
objects don’t have this method.
To do lazy interpolation, you can do something like the following:
>>> template = "The sum of %d and %d is %d."
>>> template % (x, y, x + y)
'The sum of 5 and 10 is 15.'
In this example, you create a template string with the required replacement fields. Then, you use the modulo operator to interpolate values into the template later in your code. This practice allows you to reuse the template string in several different parts of your code.
Note: Python provides many other format specifiers for the modulo operator. For a complete list, check out the printf-style String Formatting section in Python’s documentation.
To learn about other uses of Python’s modulo operator (%
), check out the Python Modulo in Practice: How to Use the % Operator tutorial.
Then, you have the modulo operator and a tuple of values or expressions. The operator will interpolate each value in this tuple into the appropriate specifier using their position.
Interpolating One or More Values
In the previous section, you saw an example where you interpolated several values or expressions into a string using the modulo operator. If you need to insert only one value, then you can skip the tuple or use a single-item tuple:
>>> "Hello, %s!" % "Pythonista"
'Hello, Pythonista!'
>>> "Hello, %s!" % ("Pythonista",)
'Hello, Pythonista!'
The first syntax is a bit cleaner than the second syntax. However, for consistency throughout your code, you may want to use the second syntax.
Now, what happens when you need to interpolate a tuple object? Here’s an example:
>>> "Interpolating a tuple: %s" % (1, 2, 3)
Traceback (most recent call last):
File "<input>", line 1, in <module>
"Interpolating a tuple: %s" % (1, 2, 3)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
TypeError: not all arguments converted during string formatting
In this example, Python interprets the tuple as three different values, and you get an error because the string has only one replacement field. To work around this issue, you need to use a single-item tuple:
>>> "Interpolating a tuple: %s" % ((1, 2, 3),)
'Interpolating a tuple: (1, 2, 3)'
Now, the interpolation works correctly, and you end up with the tuple inserted into the string. It’s important to note that you must use tuples if you intend to feed multiple values into the modulo operator:
>>> "Hello, %s! Today is %s." % [name, day]
Traceback (most recent call last):
File "<input>", line 1, in <module>
"Hello, %s! Today is %s." % [name, day]
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~
TypeError: not enough arguments for format string
>>> "The sum of %d and %d is %d." % [x, y, x + y]
Traceback (most recent call last):
File "<input>", line 1, in <module>
"The sum of %d and %d is %d." % [x, y, x + y]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
TypeError: %d format: a real number is required, not list
If you use a list
object, or another iterable, then Python will interpret it as a single object, and the interpolation will fail with a TypeError
exception.
Using Named Replacement Fields
In the previous section, you learned that you should use a tuple to provide multiple arguments to the modulo operator for string interpolation. This way, the operator inserts the values in the tuple into the target string by their position, but this isn’t that readable.
Fortunately, there’s a better way. You can also use dictionaries and named replacement fields:
>>> jane = {"name": "Jane", "job": "Python Dev"}
>>> "My name is %(name)s. I'm a %(job)s." % jane
"My name is Jane. I'm a Python Dev."
In this example, the modulo operator inserts each value using the corresponding key, which is way more readable and intuitive. To build the named replacement fields, you need to insert the name in parentheses between the %
sign and the format specifier.
Using Different String Representations
You can also use the different string representations of objects with the modulo operator for string interpolation. You already learned that the %s
conversion specifier converts the object into strings. To do this, the specifier uses the user-friendly representation from the .__str__()
special method.
To use the developer-friendly string representation provided in .__repr__()
, you can use the %r
conversion specifier.
To illustrate how to do this, you can use the Article
class again:
>>> from article import Article
>>> article = Article(
... title="String Interpolation in Python: Exploring Available Tools",
... author="Real Python",
... pub_date="2024-06-03",
... )
>>> print("%s" % article)
Article: String Interpolation in Python: Exploring Available Tools
Author: Real Python
Published: 2024-06-03
>>> print("%r" % article)
Article(
title='String Interpolation in Python: Exploring Available Tools',
author='Real Python',
pub_date='2024-06-03'
)
The resulting behavior is the same as with f-strings and the .format()
method. Again, the choice of which string representation to use will depend on your code’s target audience.
Using F-Strings vs .format()
vs %
Up to this point, you’ve learned about three different Python tools that you can use for string interpolation. One question that may arise is: Which tool should you use? As with many things, the answer is: It depends.
If you want readable syntax and good performance in string interpolation and you’re only doing eager interpolation, then f-strings are for you. If you need a tool for doing lazy string interpolation, then the .format()
method is the way to go.
In contrast, the modulo operator (%
) is an old-fashioned tool not commonly used in modern Python. You could say that this tool is almost dead. However, you may find it in legacy Python code, so it’s good to learn how it works.
The following table compares the three tools using several comparison criteria:
Feature | F-strings | .format() |
% |
---|---|---|---|
Readability | High | Medium | Low |
Supports lazy evaluation | ⛔️ | ✅ | ✅ |
Supports dictionary unpacking | ⛔️ | ✅ | ✅ |
Supports the format mini-language | ✅ | ✅ | ⛔️ |
F-strings are the clear winner in terms of readability. However, they don’t allow you to do lazy interpolation. There’s no way to use an f-string to create a reusable string template that you can interpolate later in your code.
Additionally, you can’t use a dictionary to provide the input values in one go. This doesn’t mean that you can’t interpolate dictionary keys into an f-string:
>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> f"{numbers['one']}-{numbers['two']}-{numbers['three']}"
'1-2-3'
To interpolate dictionary keys into an f-string, you need to insert the key in the desired replacement field. This can make your f-string look cluttered and hard to read and write. You’re better off using the .format()
method in such cases:
>>> "{one}-{two}-{three}".format(**numbers)
'1-2-3'
>>> "{one}-{two}".format(**numbers)
'1-2'
This code is much more readable and quicker to write than the f-string version. As an added benefit, the number of keys in the input dictionary doesn’t have to match the number of replacement fields in the template string, making the code more flexible and generic.
Finally, both f-strings and the .format()
method support the Python string formatting mini-language, which allows you to nicely format the interpolated values. For a quick example, here’s how you can format the π constant using four decimal places:
>>> import math
>>> math.pi
3.141592653589793
>>> f"{math.pi:.4f}"
'3.1416'
>>> "{pi:.4f}".format(pi=math.pi)
'3.1416'
Formatting interpolated values using the formatting mini-language is beyond the scope of this tutorial. If you want to explore this topic further, check out the Python’s Format Mini-Language for Tidy Strings tutorial.
Building Templates With the Template
Class
Python has yet another tool for performing string interpolation. In the string
module, you’ll find the Template
class. As its name suggests, this class allows you to create string templates that you can use for lazy interpolation.
You’ll find two main differences between Template
and standard string interpolation tools. With Template
, the type of interpolated values isn’t considered. The values are automatically converted into strings and then inserted into the template.
Also, Template
doesn’t support string formatting. On the other hand, the standard tools have the advantage of supporting the string formatting mini-language, which will help you fine-tune your strings.
Note: The Template
class is designed to help you create complex string-based templates that you can handle in a user-friendly way. However, in most situations, the .format()
method provides a more complete solution.
To create a template string with Template
, you need a regular Python string with embedded placeholders. These placeholders consist of two parts:
- The dollar sign (
$
) - A valid Python identifier
Valid identifiers are those that you can use as variable names in Python. They combine uppercase and lowercase letters, underscores (_
), and digits. Identifiers can’t begin with digits or match a Python keyword. For example, $name
, $age
, $Tag
, $class_
, and $item_1
are all valid placeholders.
Once you’ve created the string with the appropriate placeholders, you need to:
- Import
Template
from thestring
module - Instantiate
Template
using the template string as an argument - Perform the substitution with one of two relevant methods
Here’s a quick example of how you can use Template
in your code:
>>> from string import Template
>>> template = Template("Hello, $name! Today is $day.")
>>> template.substitute(name="John", day="Friday")
'Hello, John! Today is Friday.'
In this example, you use a template string with two placeholders, $name
and $day
, as an argument to Template
. Once you’ve instantiated the class, you can call .substitute()
to interpolate values. Note that the names of the arguments you pass to .substitute()
need to match the identifiers used in the placeholders of your template string.
In the following sections, you’ll learn more about creating template strings with the Template
class.
Building Template Strings
To create valid template strings that you can feed to the Template
class, you consider some basic rules. Here’s how PEP 292 describes these rules:
$$
is an escape; it is replaced with a single$
$identifier
names a substitution placeholder matching a mapping key of “identifier”. By default, “identifier” must spell a Python identifier as defined in [2]. The first non-identifier character after the$
character terminates this placeholder specification.${identifier}
is equivalent to$identifier
. It is required when valid identifier characters follow the placeholder but are not part of the placeholder, e.g."${noun}ification"
. (Source)
To kick things off, you’ll start with an example of how to escape the dollar sign ($
), which is required to express currency values, for example:
>>> from string import Template
>>> Template("$$$amount").substitute(amount="1,000.00")
'$1,000.00'
In this string template, the first two dollar signs escape the required dollar sign, and the last dollar sign defines the placeholder.
The second rule states that every placeholder needs a $
character followed by a valid Python identifier. Here’s an example:
>>> Template("$greeting, $who!").substitute(greeting="Hello", who="World")
'Hello, World!'
In this example, you form the placeholders using valid Python identifiers, greeting
and who
. As the second rule states, the first non-identifier character terminates the placeholder, so that’s the case of the comma after $greeting
and the exclamation point after $who
.
The third rule applies to situations where you need to substitute a word in a string, and the characters that follow the identifier are valid for building identifiers. In this situation, Python won’t know where the identifier finishes.
For example, say that you need a template that allows you to display an amount of money in USD. In this situation, you can do something like the following:
>>> Template("${amount}USD").substitute(amount="100")
'100USD'
>>> Template("$amountUSD").substitute(amount="100")
Traceback (most recent call last):
...
KeyError: 'amountUSD'
Because USD
are all characters that you can use in a valid Python identifier, you need to use the ${identifier}
placeholder style. Otherwise, you get a KeyError
.
Finally, the template string that you supply to the Template()
constructor is stored in the .template
attribute. This allows you to modify the template dynamically:
>>> greeting = Template("Hello, $name! Today is $day.")
>>> greeting.substitute(name="John", day="Friday")
'Hello, John! Today is Friday.'
>>> greeting.template = "Hello, $name! Welcome!"
>>> greeting.substitute(name="John")
'Hello, John! Welcome!'
You can modify the .template
attribute whenever you need to. However, it’s best to create new instances of Template
for every different template string in your code. This way, you’ll prevent subtle bugs or even breaking your templates.
Substituting Values With .substitute()
Up to this point, you’ve used the .substitute()
method with keyword arguments to interpolate values in your string templates. You can also use the methods with dictionaries:
>>> from string import Template
>>> numbers = {"one": 1, "two": 2, "three": 3}
>>> Template("$one-$two-$three").substitute(**numbers)
'1-2-3'
Again, when you use a dictionary as an argument to substitute()
, you need to use the dictionary unpacking operator (**
). This operator will unpack the key-value pairs into keyword arguments that will be inserted into the appropriate placeholders in the template string.
Note that the placeholder names have to match the dictionary keys. If a placeholder doesn’t match any key or if the number of keys doesn’t match the number of placeholders, then you get an error:
>>> numbers = {"one": 1, "two": 2}
>>> Template("$one-$two-$three").substitute(**numbers)
Traceback (most recent call last):
...
KeyError: 'three'
If you call .substitute()
with a dictionary whose keys don’t match all the placeholders in the template string, then you get a KeyError
.
Substituting Values With .safe_substitute()
Template
has another method that you can use to interpolate the values into the string template. The method is called .safe_substitute()
and works similarly to .substitute()
. However, when you use an incomplete or non-matching set of arguments, the method doesn’t raise a KeyError
:
>>> from string import Template
>>> numbers = {"one": 1, "two": 2}
>>> Template("$one-$two-$three").safe_substitute(**numbers)
'1-2-$three'
In this code snippet, you call .safe_substitute()
using a dictionary whose keys don’t match all the existing placeholders. Rather than getting a KeyError
exception, you get a string that literally shows the missing placeholder. It can be useful in identifying the missing values inside a view of an HTML page to render.
The .safe_substitute()
method might be an advantage of using Template
over the .format()
method:
>>> "{one}-{two}-{three}".format(**numbers)
Traceback (most recent call last):
...
KeyError: 'three'
The .format()
method doesn’t have a safe way to perform the interpolation when you use an incomplete or non-matching set of arguments.
Conclusion
You’ve learned how to do string interpolation and create new strings by inserting objects into a string template. Now you know that Python has several tools for string interpolation. These tools include f-strings, the str.format()
method, and the modulo operator (%
).
You also learned about the Template
class, which you can also use for string interpolation. This class comes in a standard-library module called string
.
In this tutorial, you’ve:
- Learned how to use f-strings for eager string interpolation
- Performed lazy string interpolation with
str.format()
- Used the modulo operator (
%
) for string interpolation - Learned when to use f-strings or
str.format()
for interpolation - Done string interpolation with the
string.Template
class
Now, you have the required skills to start creating strings using different interpolation tools. Which tool you use will depend on your specific use case.
Get Your Code: Click here to download the free sample code you’ll use to explore string interpolation tools in Python.
Take the Quiz: Test your knowledge with our interactive “String Interpolation in Python: Exploring Available Tools” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
String Interpolation in Python: Exploring Available ToolsTake this quiz to test your understanding of the available tools for string interpolation in Python, as well as their strengths and weaknesses. These tools include f-strings, the .format() method, and the modulo operator.