A Guide to Python String Format Techniques

python string formatting featured image chemistry programming

A significant part of our time is spent dealing with strings, so it is important to know how to present them in the desired way. This is what we will see in this article with several examples.

Way to format strings in Python. Currently, it is recommended to use the other forms presented later in the article. However, as there is still a lot of legacy code out there, it is important to know how to use it.

As the name suggests, position markers, such as %s, are used inside the string. For example:

print("A text will be put %s" % "here")
A text will be put here

When more than one insertion is needed, a tuple is passed with each insertion in the order it should appear in the string:

print("A text will be put %s, and %s" % ("here", "also here"))
A text will be put here, and also here

There are times when we need to pass a string that has meaning for the language interpreter, but we want the interpreter to treat it as a normal string. We call these cases raw strings. For example, \t in Python is the representation of the space of the TAB key. If we want it to be displayed literally \t instead of the space, we indicate with %r, where r is to indicate raw string:

print("Here is a TAB: \t. Now, its raw form: %r" % "\t")
Here is a TAB: 	. Now, its raw form: '\t'

Dealing with numbers

For a faithful representation of the number passed, use %s so that it is converted to a string. But manipulations can be made, such as truncation to an integer and showing the signal:

num = 13.744

print("Numbers as %s are converted to strings" % num)

print("They can also be represented as integers: %d; notice that there is no rounding" % num)

print("Showing the signal in integers: %+d" % num)
print("Showing the signal in floats: %+f" % num)
Numbers as 13.744 are converted to strings
They can also be represented as integers: 13; notice that there is no rounding
Showing the signal in integers: +13
Showing the signal in floats: +13.744000

See that the float representation had more decimals than the original number. We can modify this representation with the x.yf syntax, where x is the minimum number of characters and y, the decimal places:

print('Minimum of 5 characters with 2 decimal places: %5.2f' % num)
print('Minimum of 1 characters with 0 decimal places: %1.0f (notice the rounding)' % num)
print('Minimum of 1 characters with 5 decimal places: %1.5f' % num)
print('Minimum of 10 characters with 2 decimal places: %10.2f' % num)
print('Minimum of 10 characters with 2 decimal places: %+10.2f (with signal)' % num)
Minimum of 5 characters with 2 decimal places: 13.74
Minimum of 1 characters with 0 decimal places: 14 (notice the rounding)
Minimum of 1 characters with 5 decimal places: 13.74400
Minimum of 10 characters with 2 decimal places:      13.74
Minimum of 10 characters with 2 decimal places:     +13.74 (with signal)

Formatting with the format method

This was introduced in Python 3.0, and it is more flexible and legible than the previous method.

The format method is called on the string and the values to be inserted are passed as arguments. The position markers are indicated by curly braces {}.

For just one insertion:

print("It is going to be a text {}".format("here"))
It is going to be a text here

A great advantage of this method is to be able to pass the position of the insertion as well as the name of the variable:

print("Controling {2} {1}{0}".format("!", "order", "the"))

print("First: {a}; Second: {b}; Third: {c}".format(a=1, b="2", c=12.3))

print("The variable {p} can be reused: {p}.".format(p="(hi!)"))
Controling the order!
First: 1; Second: 2; Third: 12.3
The variable (hi!) can be reused: (hi!).

It is possible to use dictionaries to pass the values to be inserted through unpacking:

person = {"name": "Francisco", "age": 36}

print("Hello, {name}. You are {age} years old.".format(**person))
Hello, Francisco. You are 36 years old.

Alignment

With the format method, there were a great improvement in the alignment of the strings. The following example shows how to control the amount of space that the string will occupy:

print("{0:16} | {1:5}".format("Name", "Age"))
print("{0:16} | {1:5}".format("Alice", 33))
print("{0:16} | {1:5}".format("Bob", 42))
print("{0:16} | {1:5}".format("Charles", "69"))
Name             | Age  
Alice            |    33
Bob              |    42
Charles          | 69   

Note how the numeric values are aligned to the right by default, meanwhile the strings are aligned to the left. This can be changed by adding the alignment character before the number of spaces. For example, < for left alignment, > for right alignment, and ^ for center alignment:

print("{0:<8} | {1:^8} | {2:>8}".format("Left", "Center", "Right"))
print("{0:<8} | {1:^8} | {2:>8}".format(11, 22, 33))
Left     |  Center  |    Right
11       |    22    |       33

It is also possible to fill the empty spaces with a character of your choice:

print("{0:=<8} | {1:-^8} | {2:.>8}".format("Left", "Center", "Right"))
print("{0:=<8} | {1:-^8} | {2:.>8}".format(11, 22, 33))
Left==== | -Center- | ...Right
11====== | ---22--- | ......33

The alignment and width can be passed as parameters:

print('"{:{align}{width}}"'.format("text", align="^", width="10"))
"   text   "

Dealing with numbers

As with the % method, the format method can also deal with numbers. The syntax is similar, but with some novelties.

print("10 characters and 2 decimal places: {:10.2f}".format(13.579))
10 characters and 2 decimal places:      13.58

Now it is possible to control the distance from the signal to the number:

print("{:=5d}".format(-42))
print("{:=+5d}".format(42))
-  42
+  42

And it is also possible to use parameters:

print("10 characters and 2 decimal places: {:{sign}{width}.{prec}f}".format(13.579, sign="+", width=10, prec=2))
10 characters and 2 decimal places:     +13.58

Dealing with dates

The format method is also very useful for formatting dates created with the datetime module:

from datetime import datetime

print("{:%Y-%m-%d %H:%M}".format(datetime(1969, 7, 20, 22, 56)))
1969-07-20 22:56

You can have further information about the format method in the official documentation.

f-strings

From Python 3.6, f-strings were introduced, which are even more flexible and legible than the previous methods. The basic syntax is to put an f before the string and the variables to be inserted are passed inside curly braces {}:

name = "Alice"
print(f"Hello, {name}!")
Hello, Alice!

The f-strings are solved at runtime, so it is possible to use expressions inside the curly braces:

print(f"Hello, {name.upper()}!")
Hello, ALICE!

Above, the upper method was called on the name variable. It is also possible to use mathematical operations:

print(f"{2 * 21}")
42

This is so simple and yet so powerful. Let’s create the multiplication table for the number 2 in three lines of code:

print("Multiplication table for 2:")

for i in range(11):
    print(f"2 x {i:2} = {2 * i:2}")
Multiplication table for 2:
2 x  0 =  0
2 x  1 =  2
2 x  2 =  4
2 x  3 =  6
2 x  4 =  8
2 x  5 = 10
2 x  6 = 12
2 x  7 = 14
2 x  8 = 16
2 x  9 = 18
2 x 10 = 20

Note that width and alignment instructions were passed to the f-string using the same syntax as the methods seen before. Two spaces were left for the numbers so that the table is well formatted.

Dealing with numbers

The syntax is the same as the previous methods, but with the f before the string:

num = 23.45

print("10 characters and 4 decimal places: {:10.4f} (format)".format(num))

print(f"10 characters and 4 decimal places: {num:10.4f} (f-string)")
10 characters and 4 decimal places:    23.4500 (format)
10 characters and 4 decimal places:    23.4500 (f-string)

Alignment

The syntax is the same as the previous methods, but with the f before the string. And we can take advantage of running expressions:

people = {
    "alice": {"name": "Alice Smith", "age": 24, "job": "engineer"},
    "bob": {"name": "Bob Stone", "age": 30, "job": "programmer"},
    "charles": {"name": "Charles Brown", "age": 25, "job": "designer"},
}

print(f"{"Name":^14} | {"Age":^5} | {"Job":^10}")
print(f"{"-"*14} | {"-"*5} | {"-"*10}")

for person in people:
    d = people[person]
    print(f"{d['name']:<14} | {d['age']:^5} | {d['job']:>10}")
     Name      |  Age  |    Job    
-------------- | ----- | ----------
Alice Smith    |  24   |   engineer
Bob Stone      |  30   | programmer
Charles Brown  |  25   |   designer

Dealing with dates

As with the previous methods, the f-strings are also very useful for formatting dates created with the datetime module:

now = datetime.now()

print(f"{now:%Y-%m-%d %H:%M}")
2024-04-09 21:00

You can have further information about f-strings in the official documentation.

What more can we do?

We saw how to format strings in Python using three different methods. The f-strings are the most recommended, as they are more flexible and legible. However, it is important to know the other methods, as there is still a lot of legacy code out there.

Even though we have seen a lot of examples, there is still a lot to explore. For example, we can format numbers as percentages, currencies, and dates in different formats. But the basics are already here, and with them, you can already do a lot. And remember, the best way to learn is by practicing. So, open your Python interpreter and start practicing!

I hope this article has been helpful to you. If you have any questions or suggestions, please leave them in the comments.

Follow Chemistry Programming on social media.

Did you like this article? It is part of the Python Drops, a set of shorter posts focused on fundamentals talking about some aspects of the Python language and programming in general. You can read more of these articles by searching for the tag “drops” here on the website.

Until next time!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top