如何在Python中使用yaml.dump对数字输出进行四舍五入?

4
有没有一种简洁的方式来控制yaml.dump输出数字的精度?比如说,我有一个类,其中包含不同复杂度的变量,其中一些是双精度浮点数,我希望它们四舍五入到第四位。这个yaml输出仅用于显示;它不会被加载(即不会使用yaml.load)。
作为一个天真的例子,考虑下面的A类:
import yaml
class A:
    def __init__(self):
        self.a = 1/7
        self.b = 'some text'
        self.c = [1/11, 1/13, 1/17, 'some more text']

    def __repr__(self):
        return yaml.dump(self)

A()

带有输出

!!python/object:__main__.A
a: 0.14285714285714285
b: some text
c: [0.09090909090909091, 0.07692307692307693, 0.058823529411764705, some more text]

和期望输出:

!!python/object:__main__.A
a: 0.1429
b: some text
c: [0.0909, 0.0769, 0.0588, some more text]

我想这可以通过yaml.representative以一些简洁的方式来完成。 我希望避免使用字符串输出的舍入,因为实际的类结构可能更加复杂(递归等)。


我不确定为什么你不能只使用 round(number, precision) - Y2H
类结构是动态和复杂的(变量数量可能会改变)。它可以包含其他变量的类变量。我认为一个干净的方法是定义一个代表,它识别双精度数字(floatarray.float)并在连接到“dump”输出之前将它们舍入。这有意义吗? - Oleg Melnikov
说实话,我不确定是否理解你的代码。你可能需要发布更多的细节。然而,基本的概念应该是在你的类中找到一种方式来定义你想要的精度,并将其与数字一起发送到函数 round(number, precision)。要么这样,要么你需要定义另一个条件来设置precision参数,但由于我不完全理解你试图做什么,所以无法告诉你如何定义那个条件。 - Y2H
让我知道哪些地方令人困惑。我很乐意澄清。我的代码应该在您的Python控制台中运行,产生第一个输出,但我需要第二个输出。然而,我不想使用round(a,4)round(b,4)等,因为变量可能会改变。这个类的另一个实例有变量xy。我认为可以通过representative方法将舍入合并到dump本身中。这样清楚吗? - Oleg Melnikov
@Y2H 这段代码使用 pyyaml 包来序列化一个 Python 类。 - memoselyk
@memoselyk:谢谢。我不确定还需要添加什么问题来使其更清晰。到目前为止,对我来说似乎很清楚,但如果需要的话,我会很乐意增加明确性。 - Oleg Melnikov
2个回答

6
你可以手动四舍五入它:
#!/usr/bin/env python
import yaml

def float_representer(dumper, value):
    text = '{0:.4f}'.format(value)
    return dumper.represent_scalar(u'tag:yaml.org,2002:float', text)
yaml.add_representer(float, float_representer)

print(yaml.safe_dump([1 / 11, 1 / 13, 1 / 17, 'some more text']))
print(yaml.dump([1 / 11, 1 / 13, 1 / 17, 'some more text']))

输出

[0.09090909090909091, 0.07692307692307693, 0.058823529411764705, some more text]

[0.0909, 0.0769, 0.0588, some more text]

你可能需要添加更多的代码来处理边角情况,可以参考represent_float(),正如@memoselyk建议的那样。


运行得非常好。我只是在尝试将这个东西组合起来(感谢@memoselyk),但是你的输入非常有价值。 - Oleg Melnikov
@EmilyHill:你也可以使用 text = '%.4f' % value(来修复格式)。我之前没有使用它,因为我认为(似乎是错误的),它使用了不同的舍入模式,但我目前找不到反例。 - jfs
所有的建议都很棒!谢谢! - Oleg Melnikov
@EmilyHill:我进一步调查发现我是正确的:round()'%f'可能会产生不同的结果,例如,f = 0.00635; print("{0:.4f} {1}".format(f, round(f, 4)))在我的机器上Python 2.6上打印出0.0063 0.0064。在Python 3上不应该有任何区别。我已更新答案使用字符串格式化,在各种Python版本上获得统一的结果。 - jfs
很有趣。感谢您的调查和帮助。 - Oleg Melnikov

2
创建你自己的浮点数表示器representer,可以按照你的需求格式化浮点数,并用yaml.add_representer(float, my_custom_repesenter)替换现有的表示器。
在这里,你可以找到默认的浮点数表示器(链接)。你可以以此为起点,只需更改值不是[+-].inf.nan的路径,并将value转换为所需的精度。

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