[Python String] Four options about Python String Interpolation

Python String Interpolation

As of Python 3.6, f-strings are a great new way to format strings. Not only are they more readable, more concise, and less prone to error than other ways of formatting, but they are also faster!

f-strings is a New and Improved Way to Format Strings in Python.

Also called “formatted string literals,” f-strings are string literals that have an f at the beginning and curly braces {} containing expressions that will be replaced with their values. The expressions are evaluated at runtime and then formatted using the __format__ protocol. As always, the Python docs are your friend when you want to learn more.

Simple Syntax

The syntax is similar to the one you used with str.format() but less verbose. Look at how easily readable this is:

1
2
3
4
>>> name = "Eric"
>>> age = 74
>>> f"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'

It would also be valid to use a capital letter F:

1
2
>>> F"Hello, {name}. You are {age}."
'Hello, Eric. You are 74.'

Arbitrary Expressions

Because f-strings are evaluated at runtime, you can put any and all valid Python expressions in them. This allows you to do some nifty things.

You could do something pretty straightforward, like this:

1
2
>>> f"{2 * 37}"
'74'

But you could also call functions. Here’s an example:

1
2
3
4
5
6
>>> def to_lowercase(input):
... return input.lower()

>>> name = "Eric Idle"
>>> f"{to_lowercase(name)} is funny."
'eric idle is funny.'

You also have the option of calling a method directly:

1
2
>>> f"{name.lower()} is funny."
'eric idle is funny.'

You could even use objects created from classes with f-strings. Imagine you had the following class:

1
2
3
4
5
6
7
8
9
10
11
class Comedian:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age

def __str__(self):
return f"{self.first_name} {self.last_name} is {self.age}."

def __repr__(self):
return f"{self.first_name} {self.last_name} is {self.age}. Surprise!"

By default, f-strings will use __str__(), but you can make sure they use __repr__() if you include the conversion flag !r:

1
2
3
4
5
>>> new_comedian = Comedian("Eric", "Idle", "74")
>>> f"{new_comedian}"
'Eric Idle is 74.'
>>> f"{new_comedian!r}"
'Eric Idle is 74. Surprise!'

Option #2: Template Strings

Here’s one more tool for string formatting in Python: template strings. It’s a simpler and less powerful mechanism, but in some cases this might be exactly what you’re looking for.

Let’s take a look at a simple greeting example:

1
2
3
4
>>> from string import Template
>>> t = Template('Hey, $name!')
>>> t.substitute(name=name)
'Hey, Bob!'

Option #3: str.format()

This newer way of getting the job done was introduced in Python 2.6.

str.format() is an improvement on %-formatting. It uses normal function call syntax and is extensible through the __format__() method on the object being converted to a string.

With str.format(), the replacement fields are marked by curly braces {}:

1
2
>>> "Hello, {}. You are {}.".format(name, age)
'Hello, Eric. You are 74.'

You can reference variables in any order by referencing their index:

1
2
>>> "Hello, {1}. You are {0}.".format(age, name)
'Hello, Eric. You are 74.'

But if you insert the variable names, you get the added perk of being able to pass objects and then reference parameters and methods in between the braces:

1
2
3
>>> person = {'name': 'Eric', 'age': 74}
>>> "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age'])
'Hello, Eric. You are 74.'

You can also use ** to do this neat trick with dictionaries:

1
2
3
>>> person = {'name': 'Eric', 'age': 74}
>>> "Hello, {name}. You are {age}.".format(**person)
'Hello, Eric. You are 74.'

str.format() is definitely an upgrade when compared with %-formatting, but it’s not all roses and sunshine.

Code using str.format() is much more easily readable than code using %-formatting, but str.format() can still be quite verbose when you are dealing with multiple parameters and longer strings.

If you had the variables you wanted to pass to .format() in a dictionary, then you could just unpack it with .format(**some_dict) and reference the values by key in the string,

Option #4: %-formatting

This is the OG of Python formatting and has been in the language since the very beginning.

String objects have a built-in operation using the % operator, which you can use to format strings. Here’s what that looks like in practice:

1
2
3
>>> name = "Eric"
>>> "Hello, %s." % name
'Hello, Eric.'

In order to insert more than one variable, you must use a tuple of those variables. Here’s how you would do that:

1
2
3
4
>>> name = "Eric"
>>> age = 74
>>> "Hello, %s. You are %s." % (name, age)
'Hello Eric. You are 74.'

However, once you start using several parameters and longer strings, your code will quickly become much less easily readable. Things are starting to look a little messy already:

Unfortunately, this kind of formatting isn’t great because it is verbose and leads to errors, like not displaying tuples or dictionaries correctly.

Summary

If you want to render the template, Template Strings will be a good option, Otherwise it is recommended to use f-string to String Interpolation.

It is not recommended to try again str.format() or %-format.

References

[1] PEP 498 – Literal String Interpolation | Python.org - https://www.python.org/dev/peps/pep-0498/

[2] Python String Formatting Best Practices – Real Python - https://realpython.com/python-string-formatting/

[3] Python 3’s f-Strings: An Improved String Formatting Syntax (Guide) – Real Python - https://realpython.com/python-f-strings/

[4] Python String Interpolation - https://www.programiz.com/python-programming/string-interpolation

[5] Python String Interpolation. Learn the basics of string… | by Iffat Malik Gore | Towards Data Science - https://towardsdatascience.com/python-string-interpolation-829e14e1fc75