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

Jas*_*n S 2 python string-formatting python-2.7

在 Java 中:

String test1 = String.format("%7.2g", 3e9);
System.out.println(test1);
Run Code Online (Sandbox Code Playgroud)

这打印 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)
Run Code Online (Sandbox Code Playgroud)

我得到

  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
Run Code Online (Sandbox Code Playgroud)

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

一般格式。对于给定的精度 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。

跆拳道?有没有办法防止那些尾随零被删除?字符串格式化的全部目的是实现一些一致性,例如用于文本对齐。

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

Mik*_*ler 6

使用该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'))
Run Code Online (Sandbox Code Playgroud)

输出:

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
Run Code Online (Sandbox Code Playgroud)

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

1. 参数化字符串格式

除了简单的格式化:

>>> '{}'.format(3.5)
'3.5'
Run Code Online (Sandbox Code Playgroud)

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

>>> '{:5.2f}'.format(3.5)
' 3.50'
Run Code Online (Sandbox Code Playgroud)

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

>>> '{num:5.2f}'.format(num=3.5)
' 3.50'
Run Code Online (Sandbox Code Playgroud)

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

>>> '{:5.{deci}f}'.format(3.5, deci=3)
'3.500'
Run Code Online (Sandbox Code Playgroud)

2.if表达

除了if语句之外,还有一个if表达式,又名三元运算符

所以,这个表达式:

a = 1
b = 2
res = 10 if a < b else 20
Run Code Online (Sandbox Code Playgroud)

相当于这个语句:

if a < b:
    res = 10
else:
    res= 20
Run Code Online (Sandbox Code Playgroud)

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

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


mat*_*ata 5

python 所做的格式化与 C 的printf样式格式化更加一致,它还会删除转换时的尾随零g。既然python的参考实现是用C语言实现的,为什么在这种情况下要和Java保持一致呢?

使用%运算符进行字符串格式化时,相关文档是String Formatting Operations,它与您链接到的文档有一些差异,特别是它允许使用#替代形式g

替代形式使结果始终包含小数点,并且尾随零不会像其他情况那样被删除。

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

所以在你的情况下:

>>> "%#7.2g" % 3e9
3.0e+09
Run Code Online (Sandbox Code Playgroud)

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