理解字符串格式化中的 Python %g,实现 Java String.format 行为
Posted
技术标签:
【中文标题】理解字符串格式化中的 Python %g,实现 Java String.format 行为【英文标题】:Understanding the Python %g in string formatting, achieving Java String.format behavior 【发布时间】:2017-06-09 23:38:54 【问题描述】:在 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 在这两种情况下,都会从有效数字中删除不重要的尾随零,如果小数点后面没有剩余数字,也会删除小数点。
正负无穷、正负零和nans,无论精度如何,都分别格式化为inf、-inf、0、-0和nan。
0 的精度等同于 1 的精度。默认精度为 6。
WTF?有什么办法可以防止那些尾随零被删除?字符串格式化的重点是实现某种一致性,例如用于文本对齐。
有没有什么方法可以让 Java 行为(本质上是小数点右侧的有效位数)而不必从头开始重写整个事情?
【问题讨论】:
【参考方案1】:使用format
方法,您可以执行以下操作:
for num in [3e9, 3.1e9, 3.01e9, 3e2, 3.1e2, 3.01e2]:
print ('n:7.2c 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.decif'.format(3.5, deci=3)
'3.500'
2。 if
表达式
除了if
语句之外,还有一个if
表达式,也就是ternary operator。
所以,这个表达式:
a = 1
b = 2
res = 10 if a < b else 20
相当于这个语句:
if a < b:
res = 10
else:
res= 20
将两者放在一起会产生如下结果:
'num:7.2c'.format(num=num, c='e' if num > 1e4 else 'f')
【讨论】:
嗯...有趣!我想一旦我理解了你的答案,我就会接受它。 添加了一些解释以方便理解。 ;) hmmmm... 哦,所以您只是根据num
的大小选择%7.2e
和%7.2f
(顺便说一下,您需要abs
)。那样不行,这两种语言的字符串格式化逻辑之间存在根本区别。【参考方案2】:
python 所做的格式与 C 的 printf
样式格式更一致,它也为 g
转换删除尾随零。既然python的参考实现是C语言的,为什么要和Java保持一致呢?
当使用%
运算符进行字符串格式化时,相关文档为String Formatting Operations,它与您链接的文档有一些不同,特别是它允许#
替代形式g
:
替代形式导致结果始终包含小数点,并且不会像其他情况那样删除尾随零。
精度决定小数点前后的有效位数,默认为6。
所以在你的情况下:
>>> "%#7.2g" % 3e9
3.0e+09
这与str.format()
所允许的不同,#
用于启用二进制、八进制或十六进制输出的前缀(至少在 python2 中,这在 python3 中已更改)。
【讨论】:
以上是关于理解字符串格式化中的 Python %g,实现 Java String.format 行为的主要内容,如果未能解决你的问题,请参考以下文章