理解字符串格式化中的Python%g,实现Java String.format行为

时间:2017-01-24 23:08:49

标签: python python-2.7 string-formatting

在Java中:

String test1 = String.format("%7.2g", 3e9);
System.out.println(test1);

这会打印3.0e+09

在Python 2.7中,如果我运行此代码

for num in [3e9, 3.1e9, 3.01e9, 3e2, 3.1e2, 3.01e2]:
   print '%7.2g %7.2f %7.2e' % (num, num, num)

我得到了

  3e+09 3000000000.00 3.00e+09
3.1e+09 3100000000.00 3.10e+09
  3e+09 3010000000.00 3.01e+09
  3e+02  300.00 3.00e+02
3.1e+02  310.00 3.10e+02
  3e+02  301.00 3.01e+02

咦?看起来精确(.2)参数在Python %g中的处理方式与Python的%f,Python的%e或Java的%g完全不同。这是doc(我的重点):

  

一般格式。对于给定的精度p> = 1,这将数字四舍五入为p位有效数字,然后根据其大小以定点格式或科学计数法格式化结果。

     

精确的规则如下:假设使用表示类型“e”和精度p-1格式化的结果将具有指数exp。然后,如果-4< = exp< p,数字格式为表示类型'f'和精度p-1-exp。否则,使用表示类型“e”和精度p-1格式化数字。 在这两种情况下,从有效数字中删除无关紧要的尾随零,如果后面没有剩余数字,则也会删除小数点。

     

无论精度如何,正负无穷大,正负零和nans分别被格式化为inf,-inf,0,-0和nan。

     

精度0被视为等于1的精度。默认精度为6.

WTF?有没有办法防止这些尾随零被删除?字符串格式化的重点是实现一些一致性,例如用于文本对齐。

有没有办法获得Java行为(基本上是小数点右边的有效位数),而不必从头开始重写整个事物?

2 个答案:

答案 0 :(得分:2)

使用format方法,您可以执行以下操作:

for num in [3e9, 3.1e9, 3.01e9, 3e2, 3.1e2, 3.01e2]:
    print ('{n:7.2{c}} {n:7.2f} {n:7.2e}'.format(n=num, c='e' if num > 1e4 else 'f'))

输出:

3.00e+09 3000000000.00 3.00e+09
3.10e+09 3100000000.00 3.10e+09
3.01e+09 3010000000.00 3.01e+09
 300.00  300.00 3.00e+02
 310.00  310.00 3.10e+02
 301.00  301.00 3.01e+02

它有两个部分可能不太为人所知。

1。参数化字符串格式

除了简单的格式:

>>> '{}'.format(3.5)
'3.5'

并使用更详细的结果规范进行格式化:

>>> '{:5.2f}'.format(3.5)
' 3.50'

您可以在format中使用可以在字符串中访问的关键字参数:

>>> '{num:5.2f}'.format(num=3.5)
' 3.50'

您也可以将这些用于格式规范本身:

>>> '{:5.{deci}f}'.format(3.5, deci=3)
'3.500'

2。 if表达式

if语句外,还有一个if表达式,a.k.a。ternary operator

所以,这个表达式:

a = 1
b = 2
res = 10 if a < b else 20

等同于此声明:

if a < b:
    res = 10
else:
    res= 20

将两者放在一起会产生如下结果:

'{num:7.2{c}}'.format(num=num, c='e' if num > 1e4 else 'f')

答案 1 :(得分:2)

python所做的格式与C&#printf样式格式更加一致,后者也会为g转换删除尾随零。由于python的引用实现在C中,为什么在这种情况下它应该与Java保持一致?

使用%运算符进行字符串格式化时,相关文档为String Formatting Operations,与您链接的文档存在一些差异,特别是它允许使用#备用表格g

  

备用表单会导致结果始终包含小数点,并且不会删除尾随零,否则它们将被删除。

     

精度确定小数点前后的有效位数,默认为6。

所以在你的情况下:

>>> "%#7.2g" % 3e9
3.0e+09

这与str.format()允许的不同,其中#用于为二进制,八进制或十六进制输出启用前缀(至少在python2中,这在python3中已更改)。