更改默认浮动打印格式

发布于 2024-09-10 08:11:05 字数 153 浏览 3 评论 0原文

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

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

有没有办法改变默认行为?

I've some lists and more complex structures containing floats. When printing them, I see the floats with a lot of decimal digits, but when printing, I don't need all of them.
So I would like to define a custom format (e.g. 2 or 3 decimals) when floats are printed.

I need to use floats and not Decimal. Also, I'm not allowed to truncate/round floats.

Is there a way to change the default behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

情深如许 2024-09-17 08:11:05

正如 Ignacio 所说,你不可以对 C 类型进行猴子补丁。

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

我建议您找到更好的解决方案,例如仅使用 "%0.2f" printf 表示法打印浮点数:

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

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

You are not allowed to monkeypatch C types, like Ignacio said.

However, if you are terribly pressed in doing so and you know some C, you could go modify the Python interpreter source code yourself, then recompile it into a custom solution. Once I modified one of the standard behaviors for lists and it was only a moderate pain.

I suggest you find a better solution, such as just printing the floats with the "%0.2f" printf notation:

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

or

print " ".join('%0.2f' % item for item in mylist)
人间不值得 2024-09-17 08:11:05

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

This doesn't answer the more general question of floats nested in other structures, but if you just need to print floats in lists or even array-like nested lists, consider using numpy.

e.g.,

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_))

gives

[[ 1.54   2.456  3.   ]
 [-8.397  2.69  -2.   ]]
和影子一齐双人舞 2024-09-17 08:11:05
>>> 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
>>>
>>> a = 0.1
>>> a
0.10000000000000001
>>> print a
0.1
>>> print "%0.3f" % a
0.100
>>>

From the Python docs, repr(a) would give 17 digits (as seen by just typing a at the interactive prompt, but str(a) (automatically performed when you print it) rounds to 12.

Edit: Most basic hack solution...
You have to use your own class though, so...yeah.

>>> class myfloat(float):
...     def __str__(self):
...             return "%0.3f" % self.real
>>> b = myfloat(0.1)
>>> print repr(b)
0.10000000000000001
>>> print b
0.100
>>>
故人如初 2024-09-17 08:11:05

不可以,因为这需要修改 float.__str__(),但不允许您对 C 类型进行 Monkeypatch。请改用字符串插值或格式化。

No, because that would require modifying float.__str__(), but you aren't allowed to monkeypatch C types. Use string interpolation or formatting instead.

旧时模样 2024-09-17 08:11:05

我今天遇到了这个问题,我想出了一个不同的解决方案。如果您担心打印时的样子,可以将 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 中测试过这个,我不知道它是否有效。

I ran into this issue today, and I came up with a different solution. If you're worried about what it looks like when printed, you can replace the stdout file object with a custom one that, when write() is called, searches for any things that look like floats, and replaces them with your own format for them.

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

It's no good if you're just putting numbers into a string, but eventually you'll probably want to write that string to some sort of file somewhere, and you may be able to wrap that file with the above object. Obviously there's a bit of a performance overhead.

Fair warning: I haven't tested this in Python 3, I have no idea if it would work.

世态炎凉 2024-09-17 08:11:05

对于那些在pandas中工作的人:

pd.options.display.float_format = "{:,.0f}".format

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

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

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

For those working in pandas:

pd.options.display.float_format = "{:,.0f}".format

I know this is an "old" post, but when I quickly search the web to find this solution, I often get older "work-arounds". Apologies in advance if I've totally missed something.

The above code formats all floats as whole numbers with "thousands" separator. Other decimal places can be obtained from changing the format specification string.

Health warning - this can complicate debugging as all output (e.g., "print", "display" and "describe") will also output figures duly rounded. This can be problematic when some floats will display differently (i.e., rounded) when they are actually a different value.

柒夜笙歌凉 2024-09-17 08:11:05

搭载为 sympy 编写的函数(请参阅 ),我整理了一种方法来实现这一目标。
使用下面的两个函数,将每个 print(... 替换为 print_my(...)。

在我看来,这比大多数函数更简单、更易于使用且用途广泛发布了其他解决方案。

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, is_first=True, **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) or isinstance(arg, int)):
            print(arg, end='')
        elif (isinstance(arg, float)):
            print_my(sp.Float(arg), is_first=False, end='')
        elif (isinstance(arg, list)):
            print('[', end='')
            for e in arg:
                print_my(e, is_first=False, **kwargs)
                if (not (e is arg[-1])):
                    print(', ', end='')
            print(']', end='')
        elif (isinstance(arg, dict)):
            print('{', end='')
            for k in arg.keys():
                print_my(k, is_first=False, **kwargs)
                print(': ', end='')
                print_my(arg[k], is_first=False, **kwargs)
                if (not (k is list(arg.keys())[-1])):
                    print(', ', end='')
            print('}', end='')
        else:
            print(round_expr(arg, 3), end='')

        if (is_first and not(arg is args[-1])):
            print(end=sep_my)

    if is_first:
        print(end=end_my)

    return

Piggybacking on a function written for sympy (see this), I have put together a way to achieve this.
With the two functions below, replace every print(... with print_my(....

This seems to me exceedingly less contrived, easier to use, and versatile than most other solutions posted.

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, is_first=True, **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) or isinstance(arg, int)):
            print(arg, end='')
        elif (isinstance(arg, float)):
            print_my(sp.Float(arg), is_first=False, end='')
        elif (isinstance(arg, list)):
            print('[', end='')
            for e in arg:
                print_my(e, is_first=False, **kwargs)
                if (not (e is arg[-1])):
                    print(', ', end='')
            print(']', end='')
        elif (isinstance(arg, dict)):
            print('{', end='')
            for k in arg.keys():
                print_my(k, is_first=False, **kwargs)
                print(': ', end='')
                print_my(arg[k], is_first=False, **kwargs)
                if (not (k is list(arg.keys())[-1])):
                    print(', ', end='')
            print('}', end='')
        else:
            print(round_expr(arg, 3), end='')

        if (is_first and not(arg is args[-1])):
            print(end=sep_my)

    if is_first:
        print(end=end_my)

    return
2024-09-17 08:11:05

升级到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

Upgrade to Python 3.1. It doesn't use more digits than necessary.

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
撑一把青伞 2024-09-17 08:11:05

如果你使用C语言,你可以使用#define
"%*.*f" 来做到这一点,例如

printf("%*.*f",4,2,variable);

If you are using C language, you can either use #define
or "%*.*f" to do that, e.g.

printf("%*.*f",4,2,variable);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文