Understanding width and precision in Python string formatting

Learn how width and precision works in Python string formatting.

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

The answer lies in the width and precision of string formatting.

If you have learned C, C++, or Bash, you would be familiar with the `printf` function. It is used for printing formatted data to stdout.

Question - Does Python have something similar to `printf`?

Answer - Not really. Python only provides the `print` function.

However, you can mimic the behavior of `printf` by using string formatting.

This is where terms like width and precision come into play.

In this article, you will learn the intricacies of using width and precision with string formatting by comparing 3 different ways of string formatting.

What is 4 divided by 3?

Let’s print the floating-point representation of `4 divided by 3`.

Code

``````# Using % operator
print("%f"%(4/3))

# Using format method
print("{:f}".format(4/3))

# Using f-strings
print(f"{4/3:f}")``````

Output

``````1.333333
1.333333
1.333333``````

Each of the above formatting methods, produces the same output. The output of `4 divided by 3` has 6 digits after the decimal.

Let’s try to limit the number of decimal places to 3.

Code

``````# Using % operator
print("%0.3f"%(4/3))

# Using format method
print("{:0.3f}".format(4/3))

# Using f-strings
print(f"{4/3:0.3f}")``````

Output

``````1.333
1.333
1.333``````

By using `0.3f` as format placeholders, we are able to contain the number of decimal places to 3.

Understanding the structure of 0.3f

Let’s generalize `0.3f` into a formula - `x.yf`

1. `x` represents the minimum width or padding of the output string.
2. `y` represents the maximum number of characters after the decimal.
3. `f` symbolizes floating-point representation.

Let’s alter the `x` and `y` values and see how the output changes.

Code

``````# Using % operator
print("%10.2f"%(4/3))

# Using format method
print("{:10.2f}".format(4/3))

# Using f-strings
print(f"{4/3:10.2f}")``````

Output

``````      1.33
1.33
1.33``````

You can see that your result contains empty white spaces to the left of each output.

So what happened? Let’s dive in.

Understanding width and precision in Python

Stage 1 - Using only `%f` representation

If you just use `%f` representation, the output will have a width/length of 8.

Code

``````# Using % operator
print("%f"%(4/3))

# Using format method
print("{:f}".format(4/3))

# Using f-strings
print(f"{4/3:f}")``````

Output

``````1.333333
1.333333
1.333333``````

Stage 2 - Adding width

Let’s add only a `width` placeholder to `%f`.

Code

``````# Using % operator
print("%10f"%(4/3))

# Using format method
print("{:10f}".format(4/3))

# Using f-strings
print(f"{4/3:10f}")``````

When the user-defined width is different(greater or smaller) than the original width, the length of the output is changed to the user-defined width. In the above example, the new length of output will be 10 characters long.

Output

``````  1.333333
1.333333
1.333333``````

The resulting output is now right-aligned with extra 2 white space characters added as padding to the left.

However, if the user-defined width is 0, the original length of the output is maintained.

Try providing the `width` as 0. `0f` will provide the same result as using `f` floating-point representation.

Code

``````# Using % operator
print("%0f"%(4/3))

# Using format method
print("{:0f}".format(4/3))

# Using f-strings
print(f"{4/3:0f}")``````

Output

``````1.333333
1.333333
1.333333``````

Stage 3 - Adding precision

Let’s now change the number of decimal places in the output to 2. This can be done by providing the `precision` value.

Code

``````# Using % operator
print("%10.2f"%(4/3))

# Using format method
print("{:10.2f}".format(4/3))

# Using f-strings
print(f"{4/3:10.2f}")``````

Upon fixing the `precision` to 2, the resulting output will only have 2 characters after the decimal. All the other characters after the 2nd decimal places are chopped off.

Hence, the output string moves even further to the right, creating more empty white spaces.

Output

``````      1.33
1.33
1.33``````

Using width and precision with integers

Formatting integers with the Width

Formatting integers with width has a similar effect as formatting floating points.

Code

``````# Using % operator
print("%10d"%(1992))

# Using format method
print("{:10d}".format(1992))

# Using f-strings
print(f"{1992:10d}")``````

Output

``````      1992
1992
1992``````

Formatting integers with precision

However, providing precision with `%` formatting has no effect and with `f-strings` and `format` method, it throws an error.

Code/Output - precision with % operator

``````# Using % operator
print("%10.2d"%(1992))
>>>       1992``````

Code/Output - precision with format and f-strings

``````# Using format method
print("{:10.2d}".format(1992))

>>>Traceback (most recent call last):
File "some_file_location", line 5, in <module>
print("{:10.2d}".format(1992))
ValueError: Precision not allowed in integer format specifier

# Using f-strings
print(f"{1992:10.2d}")

>>>Traceback (most recent call last):
File "some_file_location", line 8, in <module>
print(f"{1992:10.2d}")
ValueError: Precision not allowed in integer format specifier``````

Using width and precision with strings

Formatting string with Width

Unfortunately, the default alignment differs between `%` formatting (old style) and formatting with `format` method and `f-strings` (new style).

The old-style defaults to right-aligned while for new style it’s left.

Code

``````# Using % operator
print("%10s"%("Pylenin"))

# Using format method
print("{:10s}".format("Pylenin"))

# Using f-strings
print(f"{'Pylenin':10s}")``````

Output

``````   Pylenin
Pylenin
Pylenin   ``````

You can change this behavior easily by using certain operators.

How to align your strings left and right?

To right-align your string, use `>` operator with the new formatting methods.

Code - To right align strings

``````# Using % operator
print("%10s"%("Pylenin"))

# Using format method
print("{:>10s}".format("Pylenin"))

# Using f-strings
print(f"{'Pylenin':>10s}")``````

Output

``````   Pylenin
Pylenin
Pylenin``````

To left-align your string, use `-` operator with the old formatting method.

Code - To left-align strings

``````# Using % operator
print("%-10s"%("Pylenin"))

# Using format method
print("{:10s}".format("Pylenin"))

# Using f-strings
print(f"{'Pylenin':10s}")``````

Output

``````Pylenin
Pylenin
Pylenin   ``````

Formatting string with precision

When you add `precision` to string formatting, the characters of the string are truncated.

Let’s say, you provide a precision of `n`. All the characters except the first `n` characters are truncated.

Code

``````# Using % operator
print("%10.2s"%("Pylenin"))

# Using format method
print("{:10.2s}".format("Pylenin"))

# Using f-strings
print(f"{'Pylenin':10.2s}")``````

Output

``````        Py
Py
Py           ``````

Subscribe to Pylenin

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe