Python 3.8 introduced formatted string literals, also called as f-strings due its
f
prefix before the string quote, which has similar functionality to the string interpolation present in PHP and recent versions of JavaScript.However, Python's f-strings are powered by a mini-language, allowing to also define precision, alignment and notation, which isn't possible without the assistance of functions in PHP or JavaScript.
The old c-style
sprintf
mechanism is still possible, although it's preferable to use the new way to format strings since the old way might be in the future deprecated and it was replaced with f-strings due its limitations.What is an f-string
An f-string is any quoted, single or double, string prefixed with an f
.
In this case, python will interpret the content inside of a curly brackets as a variable or expression that will be computed and its content will replace the string section.
>>> item = "ACME"
>>> price = 10.5
>>> quantity = 4
>>> print(f"If I buy {quantity} {item} stocks, it will cost me {price*quantity}")
If I buy 4 ACME stocks, it will cost me 42.0
While
item
variable is textual, quantity
is numerical, and price * quantity
is a mathematical expression that will output a number.Arrays, tuples and dictionaries can also be used in f-strings:
>>> q_earnings = [100, 150, 120]
>>> print(f"On the 3rd quarter, it was earned {q_earnings} with a total of {sum(q_earnings)}")
On the 3rd quarter, it was earned [100, 150, 120] with a total of 370
>>> send_to = {"address": "Acme Avenue", "zip": 555}
>>> print(f" Send letter to {send_to}")
send letter to {'address': 'Acme Avenue', 'zip': 555}
>>> print(f" Mailing Address:\n {send_to['address']}\n {send_to['zip']}")
Mailing Address:
Acme Avenue
555
Alignment and fixed-point notation in f-strings
In the presence of a numerical expression, python will convert it to a number using general notation.
>>> bacteria_growth = {"January": 0.00001, "February": 120.56, "March": 1560.67}
>>> for index, month in enumerate(bacteria_growth):
>>> print(f"| {month} | {bacteria_growth[month]} |")
| January | 1e-05 |
| February | 120.56 |
| March | 1560.67 |
If we want to present data in a pretty formatted table, the first step is to force the fixed-point notation, in order to avoid the
0.00001
to be represented as 1e-05
.The fixed-point notation is defined by adding a
:
followed by f
, representing fixed-point notation. In this case bacteria_growth[month]
becomes bacteria_growth[month]:f
.>>> bacteria_growth = {"January": 0.00001, "February": 120.56, "March": 1560.67}
>>> for index, month in enumerate(bacteria_growth):
>>> print(f"| {month} | {bacteria_growth[month]:f} |")
| January | 0.000010 |
| February | 120.560000 |
| March | 1560.670000 |
Python aligns the fields to the left by default, except for numbers which are aligned to the right. To align the fields, set enough space in order for all the letters and digits to fit the space. This is done by adding the “width” of the field after the semicolon and before the notation.
In this case
bacteria_growth[month]
becomes bacteria_growth[month]:11f
, and month
becomes month:8
.>>> bacteria_growth = {"January": 0.00001, "February": 120.56, "March": 1560.67}
>>> for index, month in enumerate(bacteria_growth):
>>> print(f"| {month:8} | {bacteria_growth[month]:11f} |")
| January | 0.000010 |
| February | 120.560000 |
| March | 1560.670000 |
Alignment direction in in f-strings
The default alignment can be overridden, which is right for numbers and left for other data types, by adding after semicolon:
<
- for left alignment.>
- for right alignment.^
- to the center.=
- to keep the-
sign to the left, and then align the rest of the numerical field to the right.
>>> sales = {"January": 156, "February": 65, "March": 90}
>>> costs = {"January": 20, "February": 165, "March": 10}
>>> sum = 0
>>> for index, month in enumerate(sales):
>>> print(f"| {month:^8} | " + # aligned to the center
>>> f"{sales[month]:<4} | " + # aligned to the left
>>> f"{'Loss' if sales[month] < costs[month] else 'Profit':>8} | " + # aligned to the right
>>> f" {sales[month] - costs[month]:=8} |") # negative sign to the left, the rest to the right
| January | 156 | Profit | 136 |
| February | 65 | Loss | - 100 |
| March | 90 | Profit | 80 |
Decimal precision in f-strings
The number of decimal places can be rounded or right padded with zeros by defining the formatter after the semicolon with the following format specifier:number:[width][.precision][type]
width
is the total number of characters that will be generated which depends on the type suffix.
This field is optional.precision
:
- for fixed-point notation is the total digits before and after the dot.
- for general notation is the total number of digits after the dot.
- for scientific notation is the total number of digits after the dot and before thee
marker.type
- defines the notation and how theprecision
field is interpreted.
-g
,G
for general notation (G
for uppercase).
-f
for fixed-point notation.
-e
,E
for floating point exponential notation (E
for uppercase).
No type defined
This is the case where no type suffix is defined.
When the precision
field is present it acts in the same manner as g
(general) type.
Without the precision
modifier, the result will have as many digits as possible for maximum accuracy.
When you don’t need any fixed output size and want maximum precision this case can be the best fit, but if you need to ensure the output isn’t bigger than a certain size, it’s better to define which type
should be used.
Although the width
field defines the maximum number of characters to be output, the final size can overflow if the precision
is too large.
The precision
field defines the total digits including the number of digits before the dot.
When the number is smaller than 1e-4
the scientific notation is used.
Value | (No type) | Comment |
---|---|---|
123.4567891 | [123.4567891] 123.4567891 | maximum precision |
123.45 | [123.45] 123.45 | maximum precision |
123.4567891 | [123.4567891] [1234567890] 123.4567891:9 | the output is bigger than width |
123456789.0 | [ 1.2e+08] [1234567890] 123456789.0:10.2 | |
123.4567891 | [ 123.5] [1234567890] 123.4567891:10.4 | precision is the number of digits |
123.4567891 | [0000123.46] [1234567890] 123.4567891:010.5 | precision is the number of digits left padded with zeros |
123.4567891 | [ 123.4568] [1234567890] 123.4567891:10.7 | precision is the number of digits |
-123.4567891 | [ -123.4568] [1234567890] -123.4567891:10.7 | precision is the number of digits |
123.4567891 | [123.4567891] [1234567890] 123.4567891:10.10 | precision is the number of digits the output is bigger than width |
1e-4 | [ 0.0001] [1234567890] 1e-4:10.4 | precision is the number of digits |
0.89e-4 | [ 8.9e-05] [1234567890] 0.89e-4:10.4 | numbers small than 1e-4 are formatted in exponential notation |
General format
The general format is defined by the g
suffix, or G
for uppercase, and it’s almost similar in all aspects to the No type defined, except when no precision
field is defined, in this case, the result it will have a maximum of 6 digits counting both the digits before and after the dot.
In case of the suffix G
and the value is smaller than 1e-4
, the E
will be represented in uppercase.
Use general format when you want to keep the total number of resulting characters under a certain value, which is the case when you want to generate well formatted tables.
Value | g | Comment |
---|---|---|
123.4567891 | [123.457] 123.4567891:g | maximum of 6 digits |
123.45 | [123.45] 123.45:g | maximum of 6 digits |
123.4567891 | [ 123.457] [1234567890] 123.4567891:9g | maximum of 6 digits |
123456789.0 | [ 1.2e+08] [1234567890] 123456789.0:10.2g | |
123.4567891 | [ 123.5] [1234567890] 123.4567891:10.4g | precision is the number of digits |
123.4567891 | [0000123.46] [1234567890] 123.4567891:010.5g | precision is the number of digits left padded with zeros |
123.4567891 | [ 123.4568] [1234567890] 123.4567891:10.7g | precision is the number of digits |
-123.4567891 | [ -123.4568] [1234567890] -123.4567891:10.7g | precision is the number of digits |
123.4567891 | [123.4567891] [1234567890] 123.4567891:10.10g | precision is the number of digits the output is bigger than width |
1e-4 | [ 0.0001] [1234567890] 1e-4:10.4g | precision is the number of digits |
0.89e-4 | [ 8.9e-05] [1234567890] 0.89e-4:10.4g | numbers small than 1e-4 are formatted in exponential notation |
Fixed point notation
The fixed point notation is defined by the f
suffix, and differs from g
notation in the following:
- The
precision
field defines the number of digits only after the dot (the decimal places). - If the
precision
field isn’t defined then it always uses 6 decimal places . - Scientific formatting is never used.
Use fixed point notation when a fixed number of decimal places is important.
Value | f | Comment |
---|---|---|
123.4567891 | [123.456789] 123.4567891:f | always uses 6 decimal places |
123.45 | [123.450000] 123.45:f | always uses 6 decimal places |
123.4567891 | [123.456789] [1234567890] 123.4567891:9f | the output is bigger than width |
123456789.0 | [123456789.00] [1234567890] 123456789.0:10.2f | precision is the number of decimal places the output is bigger than width |
123.4567891 | [ 123.4568] [1234567890] 123.4567891:10.4f | precision is the number of decimal places |
123.4567891 | [0123.45679] [1234567890] 123.4567891:010.5f | precision is the number of decimal places |
123.4567891 | [123.4567891] [1234567890] 123.4567891:10.7f | precision is the number of decimal places the output is bigger than width |
-123.4567891 | [-123.4567891] [1234567890] -123.4567891:10.7f | precision is the number of decimal places the output is bigger than width |
123.4567891 | [123.4567891000] [1234567890] 123.4567891:10.10f | precision is the number of decimal places the output is bigger than width |
1e-4 | [ 0.0001] [1234567890] 1e-4:10.4f | precision is the number of decimal places |
0.89e-4 | [ 0.0001] [1234567890] 0.89e-4:10.4f | precision is the number of decimal places |
Scientific notation
The scientific notation is defined by the e
suffix, or E
for uppercase.
In this notation, the result will always use the exponential notation.
The precision
field defines the decimal places after the dot and before the e
.
Use this notation when you need to output both big values as small, as the case of values below 1.
Value | e | Comment |
---|---|---|
123.4567891 | [1.234568e+02] 123.4567891:e | always uses 6 decimal places |
123.45 | [1.234500e+02] 123.45:e | always uses 6 decimal places |
123.4567891 | [1.234568e+02] [1234567890] 123.4567891:9e | the output is bigger than width |
123456789.0 | [ 1.23e+08] [1234567890] 123456789.0:10.2e | precision is the number of decimal places before e |
123.4567891 | [1.2346e+02] [1234567890] 123.4567891:10.4e | precision is the number of decimal places before e |
123.4567891 | [1.23457e+02] [1234567890] 123.4567891:010.5e | precision is the number of decimal places before e the output is bigger than width |
123.4567891 | [1.2345679e+02] [1234567890] 123.4567891:10.7e | precision is the number of decimal places before e the output is bigger than width |
-123.4567891 | [-1.2345679e+02] [1234567890] -123.4567891:10.7e | precision is the number of decimal places before e the output is bigger than width |
123.4567891 | [1.2345678910e+02] [1234567890] 123.4567891:10.10e | precision is the number of decimal places before e the output is bigger than width |
1e-4 | [1.0000e-04] [1234567890] 1e-4:10.4e | precision is the number of decimal places before e |
0.89e-4 | [8.9000e-05] [1234567890] 0.89e-4:10.4e | precision is the number of decimal places before e |