更改默认浮动打印格式

问题描述 投票:0回答:9

我有一些列表和包含浮点数的更复杂的结构。打印它们时,我看到带有很多十进制数字的浮点数,但是打印时,我不需要全部。 所以我想在打印浮点数时定义自定义格式(例如 2 或 3 位小数)。

我需要使用浮点数而不是十进制。另外,我不允许截断/舍入浮点数。

有办法改变默认行为吗?

python python-3.x floating-point string-formatting
9个回答
10
投票

你不被允许对 C 类型进行猴子补丁,就像 Ignacio 所说的那样。

但是,如果您迫于压力并且了解一些 C,您可以自己修改 Python 解释器源代码,然后将其重新编译为自定义解决方案。有一次我修改了列表的标准行为之一,这只是一种中等程度的痛苦。

我建议您找到更好的解决方案,例如仅使用

"%0.2f"
printf 表示法打印浮点数:

for item in mylist:
    print '%0.2f' % item,

print " ".join('%0.2f' % item for item in mylist)

6
投票
>>> a = 0.1
>>> a
0.10000000000000001
>>> print a
0.1
>>> print "%0.3f" % a
0.100
>>>

根据 Python 文档

repr(a)
会给出 17 位数字(只需在交互式提示符下键入
a
即可看到,但
str(a)
(打印时自动执行)四舍五入为 12。

编辑:最基本的黑客解决方案... 不过你必须使用自己的类,所以......是的。

>>> class myfloat(float):
...     def __str__(self):
...             return "%0.3f" % self.real
>>> b = myfloat(0.1)
>>> print repr(b)
0.10000000000000001
>>> print b
0.100
>>>

6
投票

这并不能回答嵌套在其他结构中的浮点数的更普遍的问题,但如果您只需要在列表甚至类似数组的嵌套列表中打印浮点数,请考虑使用

numpy

例如,

import numpy as np
np.set_printoptions(precision=3, suppress=False)
list_ = [[1.5398, 2.456, 3.0], 
         [-8.397, 2.69, -2.0]]
print(np.array(list_))

给予

[[ 1.54   2.456  3.   ]
 [-8.397  2.69  -2.   ]]

5
投票

不可以,因为这需要修改

float.__str__()
,但是不允许你对 C 类型进行猴子补丁。请改用字符串插值或格式化。


4
投票

我今天遇到了这个问题,我想出了一个不同的解决方案。如果您担心打印时的样子,可以将 stdout 文件对象替换为自定义文件对象,当调用 write() 时,该对象会搜索任何看起来像浮点数的内容,并将它们替换为您自己的格式他们。

class ProcessedFile(object):

    def __init__(self, parent, func):
        """Wraps 'parent', which should be a file-like object,
        so that calls to our write transforms the passed-in
        string with func, and then writes it with the parent."""
        self.parent = parent
        self.func = func

    def write(self, str):
        """Applies self.func to the passed in string and calls
        the parent to write the result."""
        return self.parent.write(self.func(str))

    def writelines(self, text):
        """Just calls the write() method multiple times."""
        for s in sequence_of_strings:
            self.write(s)

    def __getattr__(self, key):
        """Default to the parent for any other methods."""
        return getattr(self.parent, key)

if __name__ == "__main__":
    import re
    import sys

    #Define a function that recognises float-like strings, converts them
    #to floats, and then replaces them with 1.2e formatted strings.
    pattern = re.compile(r"\b\d+\.\d*\b")
    def reformat_float(input):
        return re.subn(pattern, lambda match: ("{:1.2e}".format(float(match.group()))), input)[0]

    #Use this function with the above class to transform sys.stdout.
    #You could write a context manager for this.
    sys.stdout = ProcessedFile(sys.stdout, reformat_float)
    print -1.23456
    # -1.23e+00
    print [1.23456] * 6
    # [1.23e+00, 1.23e+00, 1.23e+00, 1.23e+00, 1.23e+00, 1.23e+00]
    print "The speed of light is  299792458.0 m/s."
    # The speed of light is  3.00e+08 m/s.
    sys.stdout = sys.stdout.parent
    print "Back to our normal formatting: 1.23456"
    # Back to our normal formatting: 1.23456

如果您只是将数字放入字符串中,那是没有好处的,但最终您可能希望将该字符串写入某处的某种文件中,并且您可以使用上述对象包装该文件。显然有一点性能开销。

公平警告:我还没有在 Python 3 中测试过这个,我不知道它是否有效。


1
投票

对于那些在 pandas 工作的人:
pd.options.display.float_format = "{:,.0f}".format

我知道这是一篇“旧”帖子,但是当我快速搜索网络以找到此解决方案时,我经常会得到旧的“解决方法”。如果我完全错过了一些东西,请提前道歉。

上面的代码将所有浮点数格式化为带有“千”分隔符的整数。其他小数位可以通过更改格式规范字符串来获得。

健康警告 - 这可能会使调试复杂化,因为所有输出(例如“打印”、“显示”和“描述”)也将输出适当舍入的数字。当某些浮点数实际上是不同的值时,它们会以不同的方式显示(即四舍五入),这可能会出现问题。


0
投票

我刚刚整理了一种方法来实现这一点,至少对于 sympy 表达式,请参阅 this。 使用下面的两个函数,将每个

print(...
替换为
print_my(...
。 在我看来,与发布的大多数其他解决方案相比,这非常不做作,更易于使用且用途广泛。

我怀疑我的

round_expr
可以很容易地适应非sympy表达式,这是完整答案的缺失环节。

def round_expr(expr, num_digits):
    """Round all sp.Float numerical values in an expression to 3 decimal digits"""
    return expr.xreplace({n.evalf() : n if isinstance(n, int) else sp.Float(n, num_digits) for n in expr.atoms(sp.Number)})

def print_my(*args, **kwargs):
    end_my = kwargs['end'] if 'end' in kwargs else '\n'
    sep_my = kwargs['sep'] if 'sep' in kwargs else ' '
    for arg in args:
        if (isinstance(arg, str)):
            print(arg, end=sep_my)
        elif (isinstance(arg, int)):
            print(arg, **kwargs)
        elif (isinstance(arg, float)):
            print_my(sp.Float(arg), **kwargs)
        elif (isinstance(arg, list)):
            print('[', **kwargs)
            for e in arg:
                print_my(e, **kwargs)
                if (not (e is arg[-1])):
                    print(', ', **kwargs)
            print(']', **kwargs)
        elif (isinstance(arg, dict)):
            print('{', end='')
            for k in arg.keys():
                print_my(k, **kwargs)
                print(': ', **kwargs)
                print_my(arg[k], **kwargs)
                print(', ', **kwargs)
            print('}', **kwargs)
        else:
#            print(round_expr(arg, 3), end=sep_my)
            print(round_expr(arg, 3), **kwargs)
    print(end=end_my)
    return

-2
投票

升级到Python 3.1。它不会使用不必要的数字。

Python 3.1.2 (r312:79147, Apr 15 2010, 15:35:48) 
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1
0.1

-3
投票

如果你使用C语言,你可以使用

#define
"%*.*f"
来执行此操作,例如

printf("%*.*f",4,2,variable);
© www.soinside.com 2019 - 2024. All rights reserved.