Recommended Video Course
Formatting Floats Inside Python F-Strings
Table of Contents
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:Formatting Floats Inside Python F-Strings
You’ll often need to format and round a Pythonfloat
to display the results of your calculations neatly within strings. In earlier versions of Python, this was a messy thing to do because you needed to round your numbersfirst and then use either string concatenation or theold string formatting technique to do this for you.
Since Python 3.6, theliteral string interpolation, more commonly known as aformatted string literal orf-string, allows you to customize the content of your strings in a more readable way.
An f-string is a literal string prefixed with a lowercase or uppercase letterf
and contains zero or morereplacement fields enclosed within a pair of curly braces{...}
. Each field contains anexpression that produces a value. You can calculate the field’s content, but you can also use function calls or even variables.
While most strings have a constant value, f-strings are evaluated at runtime. This makes it possible for you to pass different data into the replacement fields of the same f-string and produce different output. This extensibility of f-strings makes them a great way to embed dynamic content neatly inside strings. However, even though f-strings have largely replaced the earlier methods, they do have their short-comings.
For example, one of the most common attacks performed on arelational database is aSQL injection attack. Often, users provide parameters to SQL queries, and if the query is formed within an f-string, it may be possible to damage a database by passing in rogue commands. F-strings can also be used in adenial-of-service attack by attackingPython’s logging module code.
In older versions of Python, f-strings had a number ofother limitations that were only fixed withPython version 3.12. This version is used throughout this tutorial.
Take a look at the example below. It shows you how to embed the result of a calculation within an f-string:
>>>f"One third, expressed as a float is:{1/3}"'One third, expressed as a float is: 0.3333333333333333'
Without any explicit rounding, once an expression has produced its value it’ll be inserted into the string using a default number of decimal places. Here, the result is shown to sixteen decimal places, which, in most cases, is more precision than you’ll ever need. So you’ll likely want to round your final answer to a more practical number of digits.
In this tutorial, you’ll learn how to use a Python f-string to format floats to meet your requirements.
Get Your Code:Click here to download the free sample code and exercise solutionsyou’ll use for learning how to format floats within f-strings in Python.
Take the Quiz: Test your knowledge with our interactive “Format Floats Within F-Strings” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Format Floats Within F-StringsIn this quiz, you'll test your understanding of how to format floats within f-strings in Python. This knowledge will let you control the precision and appearance of floating-point numbers when you incorporate them into formatted strings.
To format afloat
for neat display within a Python f-string, you can use aformat specifier. In its most basic form, this allows you to define theprecision, or number of decimal places, thefloat
will be displayed with.
The code below displays the same calculation as before, only it’s displayed more neatly:
>>>f"One third, rounded to two decimal places is:{1/3:.2f}"'One third, rounded to two decimal places is: 0.33'
To use Python’s format specifiers in a replacement field, you separate them from the expression with a colon (:
). As you can see, yourfloat
has beenrounded to two decimal places. You achieved this by adding the format specifier.2f
into the replacement field. The2
is the precision, while the lowercasef
is an example of apresentation type. You’ll see more of these later.
Note: When you use a format specifier, you don’t actually change the underlying number. You only improve its display.
Python’s f-strings also have their ownmini-language that allows you to format your output in a variety of different ways. Although this tutorial will focus on rounding, this is certainly not the only thing you can use them for. As you’ll see later, their mini-language is also used in other string formatting techniques.
In addition to displaying the result of calculations, the precision part of a format specifier can also be applied directly to variables and the return values of function calls:
>>>deftotal_price(cost):...returncost*1.2...>>>cost_price=1000>>>tax=0.2>>>f"£{1000:,.2f} + £{cost_price*tax:,.2f} = £{total_price(cost_price):,.2f}"'£1,000.00 + £200.00 = £1,200.00'
This time, you’ve used multiple replacement fields in the same string. The first one formats a literal number, the second formats the result of a calculation, while the third formats the return value from a function call. Also, by inserting a comma (,
) before the decimal point (.
) in the format specifier, you add a thousands separator to your final output.
In everyday use, you display numbers with a fixed amount of decimals, but when performing scientific or engineering calculations, you may prefer to format them usingsignificant figures. Your results are then assumed to be accurate to the number of significant figures you display them with.
If you want to round numbers to significant figures, you use the lowercase letterg
in the format specifier. You can also use an uppercaseG
, but this automatically switches the format to scientific notation for large numbers.
Suppose you have a circle with a radius of 10.203 meters. To work out the area, you could use this code:
>>>importmath>>>f"Area ={math.pi*10.203**2}"'Area = 327.0435934242156'
You decide to use the value of thepi
constant provided by Python’smath
module. While your answer certainly looks highly precise, much of it is meaningless. Any calculation is only as precise as the lowest number of significant figures in any of its components. In this case, the radius value of10.203
contains only five significant figures, which is less thanmath.pi
, so that’s what the final result should be rounded to.
A better way of coding this calculation would be:
>>>f"Area ={math.pi*10.203**2:,.5g}"'Area = 327.04'
The area, correct to five significant figures, is 327.04 square meters.
You can also use format specifiers to display numbers as percentages. To do this manually, you need to multiply the number by one hundred and append it with a percent sign (%
) before displaying it with the required amount of decimal places. You can do all of this automatically by using the%
presentation type in place of the lowercasef
org
:
>>>f"{0.1256:.1%}"'12.6%'>>>f"{0.5:.2%}"'50.00%'>>>f"{3:.2%}"'300.00%'
As you can see, the.2%
has taken care of the multiplication, rounding, and%
appendage for you automatically.
You now know how to deal with the most common scenarios where you’ll need to format floats within an f-string in Python. You’ll learn more in the next section, but before moving on, expand the section below and see if you can complete the tasks. Working through these is a great way to review and consolidate your understanding so far.
Task 1: Usingnumber = 64723.4161
, see if you can write a single line of code to produce the output shown. Apart from those needed by the format specifier, your string should contain no other numbers:
>>>number=64723.4161>>># Write your solution here'The number 64,723.4161, when rounded to two decimal places, is 64_723.42.'
Task 2: Start with the variablesnumerator = 3
anddenominator = 8
, and see if you can write a single line of code to produce the output shown. Again, your string should contain no other numbers apart from those needed by the format specifier:
>>>numerator=3>>>denominator=8>>># Write your solution here'3/8 as a percentage is 37.5%.'
Task 3: Calculate the volume of asphere whose radius is 2.340 meters. Your answer should be displayed to an appropriate number of significant figures.
You’ll find possible solutions in the downloadable materials that accompany this tutorial.
Now, it’s time to move on and learn about more ways you can enhance the display of your numbers within strings.
In addition to their precision, format specifiers contain awidth parameter. This allows you to set the total number of characters used to display the number. If your number’s length exceeds the width parameter, then additional space is assigned. Otherwise, the result will be left-padded with spaces to its specified width. Assuming you set your width to fit the largest number, each number will have the same fixed length as the others.
Fixed-length records are useful for saving to a file. Afixed-length file is one whose record fields all occupy the same number of characters. Usually, fields are padded with additional characters, most commonly trailing spaces for text and leading zeros for numbers.
Fixed-length files have been around for years, and you still see them today. Although you’ll find formats likeXML andYAML easier to read manually, fixed-length files do still offer some advantages. Your code can read fixed-length records very efficiently because each field within each record is in the same position. In contrast, XML parsers usually require more resources, particularly if you have large volumes of data to deal with.
However, fixed-length files are usually more application-specific than other formats, meaning you can’t transfer them easily between systems. Also, using a parser with XML and YAML allows you to quickly add and read additional fields. In contrast, updating fixed-length fields usually involves a major recoding of each program that needs to work with them.
To see the effect of the width parameter, take a look at the code shown below:
>>>sample=12345.6789>>>print(...f"(1) |{sample:.2f}|",...f"(2) |{sample:1.2f}|",...f"(3) |{sample:8.2f}|",...f"(4) |{sample:12.2f}|",...sep="\n",...)(1) |12345.68|(2) |12345.68|(3) |12345.68|(4) | 12345.68|
In each of these four results, the precision is set to.2f
, meaning everything is rounded to two decimal places. Because you’re dealing with numbers, they’re left-padded with blanks by default. You used anewline character (\n
) as a value separator toprint each output in its own line. You also displayed each number between pipe characters (|
) to emphasize thepadding.
In the first result, no width was specified, so the f-string took care of it for you and sized the string to contain everything before the decimal point as well as the specified two digits after.
In the second example, the width is too small to accommodate the output, so it’s resized to allow the string to fit.
In the third example, the width is exactly the size required, so there’s no padding and again the same result occurs.
The final example shows padding has been applied to the output. The width is four characters beyond that required, so four blank spaces have been inserted into the start of the string.
Unless you need this additional padding, it’s generally better to ignore the width value completely and let the f-string take care of it for you.
Note: By default, when you apply a field width parameter to a string, the padding is placed to the right:
>>>f"|{"123.45":10}|"'|123.45 |'>>>f"|{123.45:10}|"'| 123.45|'
As you can see, additional spaces have been added to the right of the string to bring its width up to10
characters. The second example shows the number is left-padded but still to the same10
characters. Had you specified a precision parameter such as.2f
for the string, you’d have generated aValueError
. Strings don’t understand precision. You’ll learn more about using strings with format specifiers later in this tutorial.
You can also control theplacement of the padding if you need to. It’s possible to left, right, and even center-align your data within the specified width:
>>>sample=12345.6789>>>print(...f"(1) |{sample:<12,.2f}|",...f"(2) |{sample:>12,.2f}|",...f"(3) |{sample:^12,.2f}|",...sep="\n",...)(1) |12,345.68 |(2) | 12,345.68|(3) | 12,345.68 |
To control your padding placement, you use the less than (<
), greater than (>
), or caret (^
) alignment options. These allow you to left, right, and center-align the number within the width value, respectively.
You may have noticed that onlythree space characters have been added, instead of thefour you saw earlier. This is because by including the thousands separator in your format specifier, you have used up an additional character space.
Now suppose you want to use padding but would instead prefer a different padding character to the default space you’ve used so far. To do this, you add your chosen padding characterbefore the alignment option:
>>>sample=12345.6789>>>print(...f"(1) |{sample:*<12.2f}|",...f"(2) |{sample:*>12.2f}|",...f"(3) |{sample:*^12.2f}|",...sep="\n",...)(1) |12345.68****|(2) |****12345.68|(3) |**12345.68**|
In this example, you’ve chosen to pad your numbers out with an asterisk (*
) character, although you could have used any other character. To do this, you added the asterisk into the format specifier. Your number was formatted to the expected two decimal places and padded out with an appropriate number of asterisks to make sure it was the12
characters wide you wanted.
In each of your examples so far, you’ve used positive numbers. Feel free to rerun any of them with negative numbers, and you’ll see that a negative sign will appear next to them. Positive numbers remain unsigned to adhere to the usual assumption that unsigned numbers are positive.
Suppose you want to display a sign against every number for emphasis or clarification, or to create fixed-length records for filing. To force the display of a sign against all of your numbers, you add the plus sign (+
) option into the format specifier as shown:
>>>sample=-12345.68>>>print(...f"(1) |{sample:12,.2f}|",...f"(2) |{sample:+12,.2f}|",...f"(3) |{-sample:+12,.2f}|",...sep="\n",...)(1) | -12,345.68|(2) | -12,345.68|(3) | +12,345.68|
This time, the number you used is negative. In the first example, when you use the12,.2f
format specifier, the negative sign appears. The second example gives you the same output, but you’ve added a plus sign to the start of the format specifer. The benefit of this only becomes apparent when you negate the number in example three. The plus sign (+
) option in the format specifier now forces the display of the plus sign in your output.
Note: There’s an age-old problem in computing with displaying calculations that result in a zero. If part of the calculation involves negatives, an annoying result may display:
>>>result=(5*0)/(-4+2)>>>print(...f"(1){result:12.1g}",...f"(2){result:+12.1f}",...sep="\n",...)(1) -0(2) -0.0
While logic tells you the answer is an unsigned zero, Python, like most languages, insists on displaying the negative sign. This happens because of how floats are represented in memory. It also happens regardless of whether you round to decimal places, significant digits, or use the plus sign in your format specifier. Usually, this is something you don’t want to see.
Fortunately,PEP 682 provides a solution that allows you to remove the pesky negative sign (-
) from zeros. To do so, youuse thez
option as shown below:
>>>print(...f"(1){result:z12.1g}",...f"(2){result:z12.1f}",...sep="\n",...)(1) 0(2) 0.0
As you can see, the negative is now gone and you’ve made things look neater.
You now know how to deal with some of the intricacies surrounding the display of rounded numbers. There are still some interesting things for you to learn, but before you move on, it’s time to put your thinking cap on again. Why not see if you can solve the following tasks?
Task 4a: Usingsample = -12345.6789
, see if you can write a single line of code to produce the output shown. The output should be left-aligned, and twelve characters wide with two decimal places of precision. Don’t forget the command separators and include all zeros:
>>>sample=-12345.6789>>>print(...# Write your solution here...)|-12,345.68 ||+12,345.68 |
Task 4b: Update your previous output so it displays like that shown below. It’s very similar to the previous output except the plus sign (+
) has been replaced with a space. Ideally, you should use a similar format specifier for both outputs. Remember to consult the Python documentation if you need help:
>>>sample=-12345.6789>>>print(...# Write your solution here...)|-12,345.68 || 12,345.68 |
Task 5: Start withresult = 5 * 3
, then see if you can produce the output shown without encoding a literal decimal point symbol (.
) onto the end of the f-string. Instead, code the trailing decimal point using an appropriate format specifier syntax:
>>>result=5*3>>>print(...# Write your solution here...)By default, the result is displayed like this: 15However, some people love trailing decimal points like this: 15.
Task 6: Start with the three variables,customer_id = "C123456"
,amount1 = 12.34
, andamount2 = 56.78
, and see if you can produce the fixed-length record as shown:
>>>customer_id="C123456">>>amount1=12.34>>>amount2=56.78>>>print(...# Write your solution here...)C12345600012.3400056.78
Thecustomer_id
should be written as is, butamount1
andamount2
should be zero-padded to a total length of eight characters and two decimal places, as shown above.
You’ll find possible solutions in the downloadable materials that accompany this tutorial.
Now that you’ve learned how to round everyday numbers and have had a chance to practice your skills, it’s time to look at how to format both large and small numbers, as well as the impossible-to-imagine complex numbers.
When you want to write very large or very small numbers concisely, you often usescientific notation. Python, like many other programming languages, usesE notation to display scientific notation, as you can see below:
In the figure above, you can see two examples of numbers formatted with scientific notation. The first uses the traditional mathematical representation, while the second uses Python’s representation.
You won’t be surprised to learn that you can display numbers with scientific notation using format specifiers. Here’s how you do it:
>>>f"{1234.56789:.2e}"'1.23e+03'>>>f"{0.00012345:.3e}"'1.234e-04'
A common specifier you might use to format numbers in scientific notation is the lowercase (e
) presentation type. This uses a lowercase lettere
in its display.
In the first example, because you set a precision of.2e
, your string will display the number in scientific notation rounded to two decimal places. It’s also possible to add a width value. As before, this simply pads out the result to fit the width where necessary.
In the second example, you are going in the other direction and displaying a very small number. As a result, the scientific notation raises the power of ten to-04
. This time, your use of.3e
has displayed the result to three decimal places.
As with all numbers you pass through a format specifier, the format specifier is only a display tool. All calculations should use the original number to retain accuracy.
You can also use format specifiers withcomplex numbers. Complex numbers are widely used in engineering and physics to solve equations relating to oscillations. They can be used, for example, as part of aFourier transform to remove noise frequencies from genuine transmissions.
A complex number is formed of both areal part and animaginary part, with the imaginary part being a multiple of the square root of negative one. They’re normally written in the forma+bi, wherea is called thereal part, andb is called theimaginary part.
Note: Python uses the letterj instead ofi to denote the imaginary part.
Despite the somewhat abstract nature of complex numbers, you’ll be glad to know that format specifiers have them covered:
>>>value=3.474+2.323j>>>print(...f"The complex number{value} is formed",...f"from the real part{value.real:.2f},",...f"the imaginary part{value.imag:.1f},",...f"and is approximately{value:.0f}.",...sep="\n",...)The complex number (3.474+2.323j) is formedfrom the real part 3.47,the imaginary part 2.3,and is approximately 3+2j.
As you can see, you access the real and imaginary components of your complex number within an f-string expression using their.real
and.imag
properties. Once you have these, you can format them in the same way you format any other number. You can also format the entire complex number at once by applying the format specifier directly to it.
In the above example,.2f
formats the real part with two decimal places, then.1f
formats the imaginary part to one decimal place. Finally,.0f
formats the complete number to zero decimal places.
Soon, you’ll move away from the basic methods of rounding numbers with format specifiers in f-strings and learn how they can be used in other ways. Before you do, it’s time for another challenge.
Task 7: Usingvalue = 13579+0.0245j
, see if you can write a single line of code to produce the output shown below:
>>>value=13579+0.0245j>>>print(...# Write your solution here...)The real part is 1.36E+04 and the imaginary part 2.45E-02.
See if you can work out the required format specifiers. Remember, you’re aiming for an uppercaseE
so you may need to read the documentation.
You’ll find possible solutions in the downloadable materials that accompany this tutorial.
decimal
Objects to Mitigate Floating Point InaccuraciesThe Pythonfloat
type limits you to 64 bits of storage for storing your numbers. This means that if any of your numbers exceed this size, they can’t be represented accurately. The code below shows an example:
>>>f"{(10000000000000/3)}"'3333333333333.3335'
The precise answer is an infinite number of recurring threes. As you can see, a trailing5
has appeared because of space limitations.
You might think that using the format specifier.2f
to display the output to two decimal places would solve the problem, but the inaccuracy is still there in the background. Format specifiers only round their data for display. They don’t truncate it.
For example, consider the following calculation:
>>>f"{(10000000000000/3)+0.6666}"'3333333333334.0'
The result not only shows that the inaccuracy still exists but the error has now entered the integer part of your result. Further calculations would compound this issue and lead to greater inaccuracies in your final result.
Although the precision issues surrounding floating-point arithmetic on computers are aninherent part of their design, if you need accuracy assurance, then you should consider using the built-indecimal
module instead.Decimal
objects provide more control over floating-point arithmetic than the built-infloat
type because they allow you to perform calculations to a consistent precision and set that precision centrally.
To see this benefit in action, take a look at the code shown below:
>>>fromdecimalimportDecimalasD>>>fromdecimalimportgetcontext>>>getcontext().prec=4>>>f"£{float("0.1")+float("0.1")+float("0.1")}"'£0.30000000000000004'>>>f"£{D("0.1")+D("0.1")+D("0.1")}"'£0.3'
Thedecimal
module is part of Python’s standard library, so you don’t need to install it. However, to access theDecimal
class from which you’ll instantiate objects, you must still import it. By importingDecimal
with the letterD
as its alias, you can use the alias when creating instances and, therefore, write more concise code.
You also import thegetcontext()
function. When you use theDecimal
objects in code, many of their key properties are managed centrally by theircontext object. Thegetcontext()
function obtains this for you. You then use its.prec
attribute to set theprecision of yourDecimal
objects. This defines the number ofsignificant figures eachDecimal
will contain.Decimal
instances are rounded to fit their precision.
Take a look at the output of the code above. When you use floats, the representation error appears. However, whenDecimal
instances are used, it’s nowhere to be seen. What’s more, the error won’t ever reappear either.
The takeaway here is that for very high precision, you should convert your strings to decimals rather than floats before you apply a format specifier. This prevents errors from filtering through to your calculations because anything that existed beyond the specified precision will have been safely removed. In addition, the decimals are more precise with a default precision of 28 places, while the floats have only about 16 places.
Note: You may be wondering if you should simply round eachfloat
value using Python’s built-inround()
function instead. This is certainly an alternative to removing representation errors, but the context object used by thedecimal
module makes it easier to change the precision of each number in one place. The library also provides theDecimal.quantize()
method to give you even finer-grained control over howDecimal
objects can be rounded.
To help you decide which precision value to use, consider the concept ofguarding figures. Suppose you are performing a calculation involving currency. Even though the result will probably containtwo decimals, intermediate calculations should usefour decimals to prevent rounding from affecting the final result. You should always use two guarding figuresbeyond the number of decimals you wish to display.
You can introduce guarding figures by using a combination of precision and format specifiers. Format specifiers can be applied toDecimal
objects in the same way they can be applied to floats:
>>>getcontext().prec=4>>>f"£{D("0.10001")+D("0.20001"):.2f}"'£0.30'
To begin with, you are adding together two numbers which contain tiny inaccuracies in their original form. Because you have set the context precision to4
significant figures, these will be removed when each string is converted into aDecimal
object. Once the calculation proceeds, the format specifier rounds the displayed answer to two decimal places.
Note: Although thedecimal
module provides excellent floating-point support, it still can’t solve the underlying rounding issues associated with floats.
Take a look at theDecimal
object shown below:
>>>D(0.1)Decimal('0.1000000000000000055511151231257827021181583404541015625')
You might have expected the answer to be0.1000
, given that the global precision is4
. The reason the precision has been ignored is because thegetcontext().prec
attribute only applies to the results of an expression and not directly to afloat
. You can force the precision to apply, but the code is a little contrived:
>>>D(0.1)*D(1)Decimal('0.1000')
By multiplying byD(1)
, you have applied the precision of four significant figures once more.
There are still a few other ways you can format numbers as strings in Python, which you’ll explore next.
Python’s built-informat()
function is another way to produce formatted strings. The function takes two arguments: the value to be formatted plus any of the format specifiers you’ve already learned about. Some examples are shown below, with their f-string equivalents included for comparison:
>>>format(-123.4567,"+9.2f")' -123.46'>>>f"{-123.456:+9.2f}"' -123.46'>>>format(0.125,".2%")'12.50%'>>>f"{0.125:.2%}"'12.50%'
As you can see, theformat()
function uses the same format specification mini-language as the more modern f-strings. Your first example uses+9.2f
to display a string representing a signed float padded to9
characters and rounded to2
decimal places. You then use.2%
to display the number to two decimal places as a percentage.
Take a moment to compare the code usingformat()
to that using the f-string, and you’ll see that the f-string version is more compact and generally more readable.
One earlier string formatting method that still has a place today is thestr.format()
method. To use this, you need to insert replacement field placeholders into the string where you want your data to be. You then add format specifiers into the placeholders to specify how you want your data to appear. Finally, you pass the data to be inserted into the string as parameters to.format()
in the same order as the placeholders.
The code example below illustrates all of this:
>>>opposite=1.234>>>adjacent=5.678>>>hypotenuse=(opposite**2+adjacent**2)**0.5>>>template="Opposite ={:0.1f}, Adjacent ={:0.2f}, Hypotenuse ={:0.3f}">>>template.format(opposite,adjacent,hypotenuse)'Opposite = 1.2, Adjacent = 5.68, Hypotenuse = 5.811'
As you can see, the placeholders use each of the parameters passed to the.format()
method in order. Although this isn’t quite as readable as the f-string alternative, you still use the same mini-language to define the formatting.
It is also possible to pass in values to.format()
by keyword. When you add these keywords into the string’s replacement fields, the corresponding values will be inserted into the string when it’s displayed:
>>>template=(..."Opposite ={opposite:0.1f}, "..."Adjacent ={adjacent:0.2f}, "..."Hypotenuse ={hypotenuse:0.3f}"...)>>>template.format(...hypotenuse=(1.234**2+5.678**2)**0.5,...adjacent=5.678,...opposite=1.234...)'Opposite = 1.2, Adjacent = 5.68, Hypotenuse = 5.811'
In this version, you pass parameters to.format()
by keyword. Notice that the order of the parameters you pass doesn’t matter. As long as the keywords match the placeholders within the curly braces in your format specifiers, Python substitutes them accordingly.
Instead of passing the individual values as keyword parameters, you can follow a common pattern that involves aPython dictionary:
>>>data={..."opposite":1.234,..."adjacent":5.678,..."hypotenuse":(1.234**2+5.678**2)**0.5,...}>>>template=(..."Opposite ={opposite:0.1f}, "..."Adjacent ={adjacent:0.2f}, "..."Hypotenuse ={hypotenuse:0.3f}"...)>>>template.format(**data)'Opposite = 1.2, Adjacent = 5.68, Hypotenuse = 5.811'
In your code, you’ve used theunpacking operator (**
) to pass the dictionarydata
into.format()
. This passes each of your dictionary keys as a separate named parameter and each of its values as the named parameter’s value.
As you can see, this code is edging closer to the syntax you use with f-strings. You could take this to the next level and create your own number formatting template:
>>>num="{:{align}{width}.{precision}f}">>>print(...num.format(...123.236,align="<",width=8,precision=2...)...)123.24
This time, you construct the format specifier by passing in your number to be formatted along with a set of named parameters to.format()
. These get applied to yournum
template, which is then used to format your number.
When you use.format()
, it’s also possible to define the format specifier dynamically at runtime. Suppose you have several words that you want to pad out to a width of four characters greater than their length. The code below shows you how to achieve this:
>>>text="Python is cool">>>padded_words=[..."{word:*^{length}}".format(word=word,length=len(word)+4)...forwordintext.split()...]>>>padded_words['**Python**', '**is**', '**cool**']
Once more, you construct the format specifier to include the name of the parameters that you’ll receive from.format()
. The word to be formatted is assigned toword
, while the dynamically calculated width is assigned tolength
. You achieve this by nesting the precision replacement field{length}
within the format specifier. The asterisk (*
) defines the padding character to be used, while the caret (^
) symbol ensures the output is centered.
Thepadded_words
list is created using alist comprehension. The.split()
method is called on the content of thetext
variable, which separates out the original string by its space characters and produces a list containing its three words. Thefor
loop then iterates over each of these and passes them to.format()
.
When eachword
is received by.format()
, its value is assigned to the variableword
, and its length plus four characters is assigned to the variablelength
. These variables are then applied to the format specifier to produce the formatted version inpadded_words
.
Pick up your thinking cap again. It’s time for more challenges.
Task 8: In the previous example, you produced this list of strings['**Python**', '**is**', '**cool**']
with code based around thestr.format()
method. See if you can rewrite this using the f-string syntax.
Task 9: Start with thenumbers = [1234.56789, 123.456789, 12.3456789, 1.23456789]
list, and see if you can write a format specifier to produce a second list namednumbers_formatted
that contains["1,234.5679", "123.457", "12.35", "1.2"]
.
As you can see, each number is rounded so that there are the same number of digits before the decimal point as there are after it.
You’ll find possible solutions in the downloadable materials that accompany this tutorial.
You have certainly worked hard in this tutorial. Now it’s time for a holiday.
If ever you need to write code that will be used internationally, you need to make sure that numbers are formatted using thelocale of the country they are running within. This will ensure your numbers and dates are formatted according to local conventions so that they are correctly understood. To support internationalization within your code, you can use Python’slocale
module.
Thelocale
module allows you to specify standard formats such as the thousands separator, currency symbol, and so on. You don’t usually need to set this explicitly on your computer because your operating system settings are used by default. However, if you want to be sure your code runs using a specific locale, you can set it explicitly.
You can find the locale your computer is currently using with thelocale.getlocale()
function:
>>>importlocale>>>locale.getlocale()('English_United Kingdom', '1252')
The computer used to run this code is using theEnglish_United Kingdom
locale. The1252
is the character encoding used by Windows when encoding each English character. Each symbol occupies a singlebyte in memory. Run the code yourself to see your locale results.
If you want to format numbers according to the locale on your computer, use then
presentation type in your format specifier:
>>>f"{-1234.567:n}"'-1234.57'>>>f"{-1234.567:.2f}"'-1234.57'
As you can see, then
format specifier on a computer using the locale('English_United Kingdom', '1252')
is equivalent to using.2f
as the format specifier. This locale dictates that the period (.
) is used as the decimal point while the negative sign is placed to the left of the number.
To really appreciate whatn
does, you need to run it across a range of locales. Fortunately, thelocale
module provides asetlocale()
function that allows you to do this. As long as your operating system supports the locales you’re interested in, you can change how numbers are displayed:
>>>sample_locales=[...("USA","en_US.UTF-8"),...("Poland","pl_PL.UTF-8"),...("UK","en_GB.UTF-8"),...("Czech Republic","cs_CZ.UTF-8"),...("Korea","ko_KR.UTF-8"),...("Germany","de_DE.UTF-8"),...("France","fr_FR.UTF-8"),...]>>>forname,locinsample_locales:..._=locale.setlocale(category=locale.LC_ALL,locale=loc)...print(...f"{name} uses",...f"{1234.567:n} and",...f"{-1234.567:n}",...)...USA uses 1,234.57 and -1,234.57Poland uses 1 234,57 and -1 234,57UK uses 1,234.57 and -1,234.57Czech Republic uses 1 234,57 and -1 234,57Korea uses 1,234.57 and -1,234.57Germany uses 1.234,57 and -1.234,57France uses 1 234,57 and -1 234,57
You’ve created a list of tuples, with each containing the name of a country and a locale. Each locale value is in the format"language_territory.codeset"
. So,"en_US.UTF-8"
specifies that United States English is used and each character is encoded with theUTF-8
standard.
Yourfor
loop iterates through each tuple insample_locales
and passes it into theset_locale()
function’slocale
parameter. This sets the locale on your computer. You also set thecategory
parameter toLC_ALL
to ensure that the locale is applied to all categories, including numbers, dates, and currencies. Finally, you intercept the locale’s name returned by the function to prevent it from being printed by your REPL.
Once your computer has a new locale set, theprint()
function shows you how each setting affects the display of positive and negative numbers in each of the countries in the sample. Once again, everything is rounded to two decimal places.
Note: You may have noticed that the numbers for the UK locale now have separators. This is because you’ve set the locale toen_GB.UTF-8
from the default used by Microsoft Windows.
If you need more control over your formatting of numeric output,locale
provides aformat_string()
function that uses format specifier codes similar to those you learned about earlier:
>>>forname,locinsample_locales:..._=locale.setlocale(category=locale.LC_ALL,locale=loc)...print(...f"{name} uses -->{locale.format_string(...f="%10.2e",val=-123456.789,grouping=True...)}"...)...USA uses --> -1.23e+05Poland uses --> -1,23e+05UK uses --> -1.23e+05Czech Republic uses --> -1,23e+05Korea uses --> -1.23e+05Germany uses --> -1,23e+05France uses --> -1,23e+05
Here, you’ve displayed each number using scientific notation in its local form. To do this, you passedf="%10.2e"
intoformat_string()
. When using this function, you must precede the format with a string formatting operator symbol (%
). You also set thegrouping
parameter toTrue
to make sure the thousands separators were applied.
Note: When you define a format using the form"%10.2e"
, you are using a similar, but not identical, formatting language to the language used by the more modern format specifiers. This time, you are using old-styleprintf-style string formatting.
If you want to display currencies, you can use thelocale.currency()
function:
>>>forname,locinsample_locales:..._=locale.setlocale(category=locale.LC_ALL,locale=loc)...print(...f"{name} uses",...f"{locale.currency(val=123456.789,grouping=True)} and",...f"{locale.currency(val=-123456.789,grouping=True)}",...)...USA uses $123,456.79 and -$123,456.79Poland uses 123 456,79 zł and -123 456,79 złUK uses £123,456.79 and -£123,456.79Czech Republic uses 123 456,79 Kč and -123 456,79 KčKorea uses ₩123,457 and ₩123,457-Germany uses 123.456,79 € and -123.456,79 €France uses 123 456,79 € and -123 456,79 €
Here, you can see how different currencies are displayed in each of the countries sampled. You used theval
andgrouping
parameters incurrency()
the same way as you did informat_string()
earlier.
That’s it, you’ve finished. You now have a solid understanding of the main ways Python allows you to round numbers within strings.
In this tutorial, you covered a lot of ground that was hopefully interesting and a little challenging. You now know how to use Python’s format specification mini-language to round and display floats andDecimal
objects in standard ways.
You also know how to deal with both scientific and complex numbers. You touched on some of the older ways to round numbers within strings, and saw how revolutionary the f-string syntax is. You even learned how to format numbers inside strings internationally.
Now that you’ve had a thorough workout formatting numbers, you should experiment further and consider delving deeper into f-strings and the format specification mini-language that supports them. There’s still lots more for you to learn.
Congratulations on completing this tutorial, and may all your strings be neat.
Get Your Code:Click here to download the free sample code and exercise solutionsyou’ll use for learning how to format floats within f-strings in Python.
Take the Quiz: Test your knowledge with our interactive “Format Floats Within F-Strings” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Format Floats Within F-StringsIn this quiz, you'll test your understanding of how to format floats within f-strings in Python. This knowledge will let you control the precision and appearance of floating-point numbers when you incorporate them into formatted strings.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:Formatting Floats Inside Python F-Strings
🐍 Python Tricks 💌
Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.
AboutIan Eyre
Ian is an avid Pythonista and Real Python contributor who loves to learn and teach others.
» More about IanMasterReal-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
MasterReal-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.
Keep Learning
Recommended Video Course:Formatting Floats Inside Python F-Strings
Related Tutorials:
Already have an account?Sign-In
Almost there! Complete this form and click the button below to gain instant access:
How to Format Floats Within F-Strings in Python (Sample Code)