\( \newcommand{\NOT}{\neg} \newcommand{\AND}{\wedge} \newcommand{\OR}{\vee} \newcommand{\XOR}{\oplus} \newcommand{\IMP}{\Rightarrow} \newcommand{\IFF}{\Leftrightarrow} \newcommand{\TRUE}{\text{True}\xspace} \newcommand{\FALSE}{\text{False}\xspace} \newcommand{\IN}{\,{\in}\,} \newcommand{\NOTIN}{\,{\notin}\,} \newcommand{\TO}{\rightarrow} \newcommand{\DIV}{\mid} \newcommand{\NDIV}{\nmid} \newcommand{\MOD}[1]{\pmod{#1}} \newcommand{\MODS}[1]{\ (\text{mod}\ #1)} \newcommand{\N}{\mathbb N} \newcommand{\Z}{\mathbb Z} \newcommand{\Q}{\mathbb Q} \newcommand{\R}{\mathbb R} \newcommand{\C}{\mathbb C} \newcommand{\cA}{\mathcal A} \newcommand{\cB}{\mathcal B} \newcommand{\cC}{\mathcal C} \newcommand{\cD}{\mathcal D} \newcommand{\cE}{\mathcal E} \newcommand{\cF}{\mathcal F} \newcommand{\cG}{\mathcal G} \newcommand{\cH}{\mathcal H} \newcommand{\cI}{\mathcal I} \newcommand{\cJ}{\mathcal J} \newcommand{\cL}{\mathcal L} \newcommand{\cK}{\mathcal K} \newcommand{\cN}{\mathcal N} \newcommand{\cO}{\mathcal O} \newcommand{\cP}{\mathcal P} \newcommand{\cQ}{\mathcal Q} \newcommand{\cS}{\mathcal S} \newcommand{\cT}{\mathcal T} \newcommand{\cV}{\mathcal V} \newcommand{\cW}{\mathcal W} \newcommand{\cZ}{\mathcal Z} \newcommand{\emp}{\emptyset} \newcommand{\bs}{\backslash} \newcommand{\floor}[1]{\left \lfloor #1 \right \rfloor} \newcommand{\ceil}[1]{\left \lceil #1 \right \rceil} \newcommand{\abs}[1]{\left | #1 \right |} \newcommand{\xspace}{} \newcommand{\proofheader}[1]{\underline{\textbf{#1}}} \)

12.2 String Interpolation with f-strings

One common programming task that arises when writing software is generating text to display. For example, given a student’s name and student number, we might want to create a label for the student’s record in the form '<family_name>, <given_name> (<student_number>)'.

The main tool we’ve covered for accomplishing the task of building up strings is string concatenation:

>>> family_name = 'Liu'
>>> given_name = 'David'
>>> student_number = 123456789
>>> family_name + ', ' + given_name + ' (' + str(student_number) + ')'
'Liu, David (123456789)'

While this code is correct, it has two somewhat annoying features: first, we must use + to combine our variables like family_name with string literal segments like ', '; and second, we must be careful to convert student_number into a string to be able to concatenate it with the other strings.

In this section, we’ll introduce a new type of Python syntax that solves both of these problems, enabling us to more elegantly combine Python data with string literals to generate new text.

The f-string

First, a bit of review. Recall that in Python, a string literal is some text surrounded by either single- or double-quotes, e.g. 'David' or "Hello world!". String literals are the simplest kind of expression in Python that evaluates to a string; they represent text that should be literally interpreted as a string, rather than Python code.

In contrast, an f-string, short for formatted string literal, is a Python expression that looks like a regular string literal, except that the first quote is preceded by an f. For example, f'David' and f"Hello world!" are f-strings. These two examples of f-strings evaluate to the same strings as the corresponding string literals:

>>> f'David'
'David'
>>> f"Hello world!"
'Hello world!'

Okay, so what’s the point? There is one key difference between string literals and f-strings: in an f-string, any text surrounded by curly braces ({...}) is interpreted as a Python expression, which is evaluated, converted into a string, and then inserted back into the literal. In other words, f-strings give us the ability to add Python code “inside a string literal”, giving us an easy way to build up new strings!

To illustrate this, let’s return to our above example of student name and number, now using an f-string.

>>> # Same variables as before
>>> family_name = 'Liu'
>>> given_name = 'David'
>>> student_number = 123456789

>>> # Now, using an f-string
>>> f'{family_name}, {given_name} ({student_number})'
'Liu, David (123456789)'

Amazing! By writing {family_name}, the Python interpreter evaluates the variable family_name, then inserts the value in the string. The same is true for {given_name} and {student_number}, and in the latter case the Python interpreter automatically converts the int value 123456789 into a string for us.

Computing expressions in f-strings

Even though f-strings are most commonly used to insert variable values into strings, we can include almost any Python expression inside curly braces.One exception is that we cannot include quotes inside the curly braces that conflict with the quotes used around the full string literal.

For example, if we wanted the student’s family name to appear in ALL CAPS, we could call the str.upper method directly in the f-string:

>>> f'{family_name.upper()}, {given_name} ({student_number})'
'LIU, David (123456789)'

Or, if we wanted to retrive just the last four digits of the student number, we could use the modulo operator %:

>>> f'{family_name}, {given_name} ({student_number % 10000})'
'Liu, David (6789)'

We encourage you to experiment with f-strings on your own, and make use of them when generating text in your own Python programs in the future!