Making it look right

It's nice to be able to include variables in template strings, but sometimes the variables need a bit of coercion to make them look the way we want them to in the output. For example, if we are performing calculations with currency, we may end up with a long decimal that we don't want to show up in our template:

subtotal = 12.32
tax = subtotal * 0.07
total = subtotal + tax

print(
"Sub: ${0} Tax: ${1} Total: ${total}".format(
subtotal, tax, total=total
)
)

If we run this formatting code, the output doesn't quite look like proper currency:

Sub: $12.32 Tax: $0.8624 Total: $13.182400000000001
Technically, we should never use floating-point numbers in currency calculations like this; we should construct decimal.Decimal() objects instead. Floats are dangerous because their calculations are inherently inaccurate beyond a specific level of precision. But we're looking at strings, not floats, and currency is a great example for formatting!

To fix the preceding format string, we can include some additional information inside the curly braces to adjust the formatting of the parameters. There are tons of things we can customize, but the basic syntax inside the braces is the same. After providing the template value, we include a colon, and then some specific syntax for the formatting. Here's an improved version:


print(
"Sub: ${0:0.2f} Tax: ${1:0.2f} "
"Total: ${total:0.2f}".format(subtotal, tax, total=total)
)

The 0.2f format specifier after the colons basically says the following, from left to right:

We can also specify that each number should take up a particular number of characters on the screen by placing a value before the period. This can be useful for outputting tabular data, for example:

orders = [("burger", 2, 5), ("fries", 3.5, 1), ("cola", 1.75, 3)]

print("PRODUCT QUANTITY PRICE SUBTOTAL")
for product, price, quantity in orders:
subtotal = price * quantity
print(
f"{product:10s}{quantity: ^9d} "
f"${price: <8.2f}${subtotal: >7.2f}"
)

OK, that's a pretty scary-looking format string, so let's see how it works before we break it down into understandable parts:

PRODUCT    QUANTITY    PRICE    SUBTOTAL
burger        5        $2.00    $  10.00
fries         1        $3.50    $   3.50
cola          3        $1.75    $   5.25  

Nifty! So, how is this actually happening? We have four variables we are formatting, in each line of the for loop. The first variable is a string that is formatted with {product:10s}. This one is easier to read from right to left:

The formatter for the quantity value is{quantity: ^9d}. You can interpret this format from right to left as follows:

All these specifiers have to be in the right order, although all are optional: fill first, then align, then the size, and finally, the type.

We do similar things with the specifiers for price and subtotal. For price, we use {2:<8.2f}; and for subtotal, {3:>7.2f}. In both cases, we're specifying a space as the fill character, but we use the < and > symbols, respectively, to represent that the numbers should be aligned to the left or right within a minimum space of eight or seven characters. Further, each float should be formatted to two decimal places.

The type character for different types can affect formatting output as well. We've seen the s, d, and f types, for strings, integers, and floats. Most of the other format specifiers are alternative versions of these; for example, o represents octal format and X represents hexadecimal if formatting integers. The n type specifier can be useful for formatting integer separators in the current locale's format. For floating-point numbers, the % type will multiply by 100 and format a float as a percentage.