如何将小数格式化为始终显示2个小数位?

373

我想显示:

49 显示为 49.00

和:

54.9 显示为 54.90

无论小数部分的长度如何,或者是否有任何小数位,我都希望以高效的方式显示具有 2 个小数位的 Decimal 值。目的是显示货币值。

例如,4898489.00


有关内置的 float 类型的类似问题,请参见限制浮点数精度到小数点后两位


我猜这可能意味着OP正在使用decimal.Decimal,并对十进制上下文的精度感到不满,因为它将精度限制为n位,例如“严格意义上的n位精度”(例如'123.456'变成Decimal('1.2E+2')),而不是“小数部分的n位”(对于Decimal('123.45'))...请参见我的答案,希望能对此有所帮助。;-) - Michał Marczyk
1
是的,它们是用于货币价值的。 - orokusaki
13个回答

724

您应该使用新的格式规范来定义值应如何表示:

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

有时文档可能有点晦涩难懂,因此我建议参考以下易于阅读的文献:

Python 3.6引入了字面字符串插值(也称为f字符串),因此现在您可以更加简洁地编写上述内容:

>>> f'{pi:.2f}'
'3.14'

6
@Droogans说:"format"确实返回一个字符串而不是浮点数:"print type({0:.2f}".format(pi))"返回"<type 'str'>"。 - BioGeek
糟糕,对于“return”这个词使用了动词重载。请在心里将其改为“print”。 - yurisich
25
如果您不想使用数字占位符:"{:.2f}".format(pi) - User
1
0:是什么意思?我猜.是Python字符串的一部分。 - information_interchange
1
@information_interchange:0 表示它是传递给 format 函数的第一个参数。如果您想打印类似于 '{0} is bigger than {1}'.format(5, 4) 的内容,请参见 https://dev59.com/M3RB5IYBdhLWcg3wxZ_Y#517471 获取详细信息。 - Stadem

159

Python文档中的字符串格式化操作部分包含了你要寻找的答案。简言之:

"%0.2f" % (num,)

一些示例:

>>> "%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'

1
%后面不需要加上0,也不需要用tuplenum包裹起来。 - user238424
20
将num放在元组中是一种编码规范,以防止在字符串格式化期间的参数鸭子类型错误。这在进行浮点数转换时在本例中没有任何效果,但它可以防止在转换为字符串时出现意外的类型错误。比较下面两个例子:r = 1; "%s" % r; r = (1, 2); "%s" % rr = 1; "%s" % (r,); r = (1,2 ); "%s" % (r,)。因此,在Python中,大多数复杂的编码风格现在都使用无条件的元组(Python 3已将整个字符串格式化方法作为容易出错的方法弃用)。 - Travis Bradshaw

136
我想你可能正在使用decimal模块中的Decimal()对象?(如果你需要任意大的数字保留小数点后两位精度,那么你肯定应该这样做,而且这也是你问题标题所示的内容...)
如果是这样,文档中的Decimal FAQ部分有一个问题/答案对可能对你有用:

Q. 在具有两个小数位的定点应用程序中,一些输入具有许多位并需要四舍五入。其他输入不应具有额外的数字,并需要进行验证。应使用哪些方法?

A. quantize()方法将数据四舍五入到固定的小数位数。如果设置了Inexact trap,它也可用于验证:

>>> 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

下一个问题是:

Q. 一旦我有了有效的两个输入,如何在整个应用程序中保持这个不变量?

如果您需要答案(以及许多其他有用的信息),请参见文档中上述部分。此外,如果您将Decimal保留两位小数(意味着尽可能多地保留小数点左侧的所有数字和右侧的两个数字,但不要超过...),那么使用str将其转换为字符串就可以正常工作:

str(Decimal('10'))
# -> '10'
str(Decimal('10.00'))
# -> '10.00'
str(Decimal('10.000'))
# -> '10.000'

2
哦,忘了在答案中提及效率...但我想我也不是专家。 我看不出为什么保留固定数量的“小数位数”会特别低效 - 尽管对数字执行的任何操作可能需要对结果进行舍入操作以使其符合要求... 为了效率起见,这应该尽可能少地进行 - 就像在序列化/打印给用户之前。 - Michał Marczyk

44
>>> print "{:.2f}".format(1.123456)
1.12

你可以更改 2 中的数字,以显示想要展示的小数位数。

编辑:

Python3.6 开始,这将被翻译为:

>>> print(f"{1.1234:.2f}")
1.12

38
你可以使用字符串格式化运算符来实现此操作:字符串格式化运算符
num = 49
x = "%.2f" % num  # x is now the string "49.00"

我不确定你所说的“高效”是什么意思——这几乎肯定不是你的应用程序的瓶颈。如果你的程序运行缓慢,请先进行性能分析以找出热点,然后对其进行优化。


1
我认为将变量命名为“f”可能会让一些人感到困惑。最好为像下面的Travis这样的示例给它取一个别的名字。 - Aleck Landgraf

25

.format 是一种更易读的处理变量格式的方式:

'{:.{prec}f}'.format(26.034, prec=2)

我从没想过你可以像这样嵌套格式。非常酷。 - Mathieson

23
在Python 3中,一种实现这个的方法是:
'{:.2f}'.format(number)

8
如果您有多个参数,可以使用以下方法:
 print('some string {0:.2f} & {1:.2f}'.format(1.1234,2.345))
 >>> some string 1.12 & 2.35

8

OP始终希望显示两位小数,因此仅调用格式化函数并不够好,就像其他答案所做的那样。

正如其他人已经指出的那样,Decimal 对于货币非常有效。但是,Decimal 显示了所有小数位。因此,需要覆盖其显示格式:

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

使用方法:

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

简单。

编辑:

要显示至少两位小数,但截断有效数字:

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

我希望Python的未来版本能够改进数字格式,以允许指定最小小数位数。类似于Excel数字格式中的 # 符号。


4
如果你用于货币,同时也想让值用,分隔,可以使用 $ {:,.f2}.format(currency_value)
例如: currency_value = 1234.50 $ {:,.f2}.format(currency_value) --> $ 1,234.50 这是我一段时间前写的代码: print("> 在" + year_string + "年末,总支付金额为 \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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接