364

I want to display:

49 as 49.00

and:

54.9 as 54.90

Regardless of the length of the decimal or whether there are are any decimal places, I would like to display a Decimal with 2 decimal places, and I'd like to do it in an efficient way. The purpose is to display money values.

eg, 4898489.00


For the analogous issue with the built-in float type, see Limiting floats to two decimal points.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
orokusaki
  • 55,146
  • 59
  • 179
  • 257
  • I suppose it might mean that the OP is using decimal.Decimal and is unhappy with decimal context's precision which limits precision to n digits as in "n digits of precision in the strict sense" (e.g. '123.456' becomes Decimal('1.2E+2')) and not "n digits in the fractional part" (for Decimal('123.45'))... See my answer for an attempt to be helpful with this. ;-) – Michał Marczyk Jan 03 '10 at 19:02
  • 1
    Yes, they are for money values. – orokusaki Jan 03 '10 at 19:03

13 Answers13

713

You should use the new format specifications to define how your value should be represented:

>>> from math import pi  # pi ~ 3.141592653589793
>>> '{0:.2f}'.format(pi)
'3.14'

The documentation can be a bit obtuse at times, so I recommend the following, easier readable references:

Python 3.6 introduced literal string interpolation (also known as f-strings) so now you can write the above even more succinct as:

>>> f'{pi:.2f}'
'3.14'
0 _
  • 10,524
  • 11
  • 77
  • 109
BioGeek
  • 21,897
  • 23
  • 83
  • 145
  • 6
    @Droogans: Euh... `format` does return a `str`, not a `float`: `print type({0:.2f}".format(pi))` returns ``. – BioGeek Feb 22 '12 at 08:57
  • Oops. Verb overloading on the word `return`. Please mentally change that to `print`s. – yurisich Feb 22 '12 at 11:57
  • 25
    If you don't want to use the numeric placeholder: `"{:.2f}".format(pi)` – User May 31 '14 at 00:48
  • 1
    What does the `0:` do? I assume the `.` is part of the python string – information_interchange Oct 18 '19 at 03:43
  • 1
    @information_interchange: `0` means it's the first argument passed to the `format` function. In case you wanted to print something like `'{0} is bigger than {1}'.format(5, 4)` See https://stackoverflow.com/a/517471 for details. – Stadem Nov 04 '20 at 00:25
158

The String Formatting Operations section of the Python documentation contains the answer you're looking for. In short:

"%0.2f" % (num,)

Some examples:

>>> "%0.2f" % 10
'10.00'
>>> "%0.2f" % 1000
'1000.00'
>>> "%0.2f" % 10.1
'10.10'
>>> "%0.2f" % 10.120
'10.12'
>>> "%0.2f" % 10.126
'10.13'
jesterjunk
  • 2,342
  • 22
  • 18
Travis Bradshaw
  • 4,272
  • 3
  • 22
  • 20
  • 1
    There's no need for the `0` after the `%`, and no need to wrap `num` in a `tuple`. – user238424 Jan 03 '10 at 23:32
  • 20
    Actually, wrapping num in a tuple is a coding convention to prevent a duck typing error on arguments during string formatting. It doesn't have any effect in this case with a float conversion, but it prevents an unexpected type error when converting to strings. Consider `r = 1; "%s" % r; r = (1, 2); "%s" % r` versus `r = 1; "%s" % (r,); r = (1,2 ); "%s" % (r,)`. As such, most sophisticated coding styles in python use the unconditional tuple now (and Python 3 deprecated the entire method of string formatting as error prone). – Travis Bradshaw Jan 04 '10 at 01:06
134

I suppose you're probably using the Decimal() objects from the decimal module? (If you need exactly two digits of precision beyond the decimal point with arbitrarily large numbers, you definitely should be, and that's what your question's title suggests...)

If so, the Decimal FAQ section of the docs has a question/answer pair which may be useful for you:

Q. In a fixed-point application with two decimal places, some inputs have many places and need to be rounded. Others are not supposed to have excess digits and need to be validated. What methods should be used?

A. The quantize() method rounds to a fixed number of decimal places. If the Inexact trap is set, it is also useful for validation:

>>> TWOPLACES = Decimal(10) ** -2       # same as Decimal('0.01')
>>> # Round to two places
>>> Decimal('3.214').quantize(TWOPLACES)
Decimal('3.21')
>>> # Validate that a number does not exceed two places
>>> Decimal('3.21').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Decimal('3.21')
>>> Decimal('3.214').quantize(TWOPLACES, context=Context(traps=[Inexact]))
Traceback (most recent call last):
   ...
Inexact: None

The next question reads

Q. Once I have valid two place inputs, how do I maintain that invariant throughout an application?

If you need the answer to that (along with lots of other useful information), see the aforementioned section of the docs. Also, if you keep your Decimals with two digits of precision beyond the decimal point (meaning as much precision as is necessary to keep all digits to the left of the decimal point and two to the right of it and no more...), then converting them to strings with str will work fine:

str(Decimal('10'))
# -> '10'
str(Decimal('10.00'))
# -> '10.00'
str(Decimal('10.000'))
# -> '10.000'
Community
  • 1
  • 1
Michał Marczyk
  • 83,634
  • 13
  • 201
  • 212
  • 2
    Oh, forgot to mention efficiency in the answer... but I guess I'm no expert anyway. I see no reason why it would be particularly inefficient to keep a fixed number of "fractional digits" around -- although any operations performed on the numbers might necessitate a rounding operation on the result to bring it in line with the requirements... For efficiency's sake, this should probably be done as infrequently as possible -- like just prior to serialisation / printing out for the user. – Michał Marczyk Jan 03 '10 at 18:54
44
>>> print "{:.2f}".format(1.123456)
1.12

You can change 2 in 2f to any number of decimal points you want to show.

EDIT:

From Python3.6, this translates to:

>>> print(f"{1.1234:.2f}")
1.12
Aziz Alto
  • 19,057
  • 5
  • 77
  • 60
38

You can use the string formatting operator as so:

num = 49
x = "%.2f" % num  # x is now the string "49.00"

I'm not sure what you mean by "efficient" -- this is almost certainly not the bottleneck of your application. If your program is running slowly, profile it first to find the hot spots, and then optimize those.

mit
  • 11,083
  • 11
  • 50
  • 74
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 1
    I think the variable being named 'f' might confuse some people. Better to call it something else for an example like Travis below. – Aleck Landgraf Dec 10 '12 at 05:44
25

.format is a more readable way to handle variable formatting:

'{:.{prec}f}'.format(26.034, prec=2)
Mayank Patel
  • 359
  • 3
  • 4
23

In python 3, a way of doing this would be

'{:.2f}'.format(number)
user443854
  • 7,096
  • 13
  • 48
  • 63
Devin Ersoy
  • 354
  • 3
  • 12
8

if you have multiple parameters you can use

 print('some string {0:.2f} & {1:.2f}'.format(1.1234,2.345))
 >>> some string 1.12 & 2.35
sushmit
  • 4,369
  • 2
  • 35
  • 38
7

The OP always wants two decimal places displayed, so explicitly calling a formatting function, as all the other answers have done, is not good enough.

As others have already pointed out, Decimal works well for currency. But Decimal shows all the decimal places. So, override its display formatter:

class D(decimal.Decimal):
    def __str__(self):
        return f'{self:.2f}'  

Usage:

>>> cash = D(300000.991)
>>> print(cash)
300000.99

Simple.

EDIT:

To display at least two decimal places but without truncating significant digits:

class D(decimal.Decimal):
    def __str__(self):
        """Display at least two decimal places."""
        result = str(self)
        i = result.find('.')
        if i == -1:
             # No '.' in self. Pad with '.00'.
             result += '.00'
        elif len(result[i:]) == 2:
             # One digit after the decimal place. Pad with a '0'.
             result += '0'
        return result

I hope that a future version of Python will improve the number formatting to allow minimum decimal places. Something like the # sign in Excel's number formatting.

ChaimG
  • 7,024
  • 4
  • 38
  • 46
4

If you're using this for currency, and also want the value to be seperated by ,'s you can use

$ {:,.f2}.format(currency_value).

e.g.:

currency_value = 1234.50

$ {:,.f2}.format(currency_value) --> $ 1,234.50

Here is a bit of code I wrote some time ago:

print("> At the end of year " + year_string + " total paid is \t$ {:,.2f}".format(total_paid))

> At the end of year   1  total paid is         $ 43,806.36
> At the end of year   2  total paid is         $ 87,612.72
> At the end of year   3  total paid is         $ 131,419.08
> At the end of year   4  total paid is         $ 175,225.44
> At the end of year   5  total paid is         $ 219,031.80   <-- Note .80 and not .8
> At the end of year   6  total paid is         $ 262,838.16
> At the end of year   7  total paid is         $ 306,644.52
> At the end of year   8  total paid is         $ 350,450.88
> At the end of year   9  total paid is         $ 394,257.24
> At the end of year  10  total paid is         $ 438,063.60   <-- Note .60 and not .6
> At the end of year  11  total paid is         $ 481,869.96
> At the end of year  12  total paid is         $ 525,676.32
> At the end of year  13  total paid is         $ 569,482.68
> At the end of year  14  total paid is         $ 613,289.04
> At the end of year  15  total paid is         $ 657,095.40   <-- Note .40 and not .4  
> At the end of year  16  total paid is         $ 700,901.76
> At the end of year  17  total paid is         $ 744,708.12
> At the end of year  18  total paid is         $ 788,514.48
> At the end of year  19  total paid is         $ 832,320.84
> At the end of year  20  total paid is         $ 876,127.20   <-- Note .20 and not .2
3kstc
  • 1,871
  • 3
  • 29
  • 53
3

This is the same solution as you have probably seen already, but by doing it this way it's more clearer:

>>> num = 3.141592654

>>> print(f"Number: {num:.2f}")

Tobdu
  • 31
  • 1
1

The Easiest way example to show you how to do that is :

Code :

>>> points = 19.5 >>> total = 22 >>>'Correct answers: {:.2%}'.format(points/total) `

Output : Correct answers: 88.64%

-6

what about

print round(20.2564567 , 2)    >>>>>>>        20.25


print round(20.2564567 , 4)    >>>>>>>        20.2564
Mahmoud Hamdy
  • 59
  • 1
  • 1
  • 8
  • People voted this down because `print round(20,2)` will round 20 to the nearest hundredth to get 20.00 and then print 20. `round` changes the value of the argument sent to print, but does not o anything to format the output of print as requested by OP. – Bennett Brown May 07 '22 at 17:34