【问题标题】:How can I locale-format a python Decimal and preserve its precision?如何对 python Decimal 进行语言环境格式化并保持其精度?
【发布时间】:2015-08-10 02:12:23
【问题描述】:

如何使用语言环境格式化 Decimal

为了举例说明,我试图定义一个函数f,以便在美国英语语言环境中:

  • f(Decimal('5000.00')) == '5,000.00'

  • f(Decimal('1234567.000000')) == '1,234,567.000000'

一些不起作用的东西:

  • f = str 不使用语言环境; f(Decimal('5000.00')) == '5000.00'

  • f = lambda d: locale.format('%f', d) 不保留小数精度; f(Decimal('5000.00')) == '5000.000000'

  • f = lambda d: locale.format('%.2f', d) 使用固定精度,这不是我想要的; f(Decimal('1234567.000000')) == '1234567.00'

【问题讨论】:

  • 我假设您知道使用例如format(Decimal('1234567.8000'), '6,f') -> '1,234,567.8000' 很容易获得数千个分隔符。困难的部分是适应当前的语言环境。
  • 我找到了一个声称可以使用其format_decimal 方法执行此操作的库,但未能保持完整的精度:babel.pocoo.org/docs/numbers 如果达到满意的答案,贡献者可能会考虑提交拉取请求针对该库来解决问题。

标签: python decimal


【解决方案1】:

阅读decimal 模块的源代码,Decimal.__format__ 提供完整的PEP 3101 支持,您所要做的就是选择正确的演示类型。在这种情况下,您需要 :n 类型。根据 PEP 3101 规范,:n 具有以下属性:

'n' - 数字。这与 'g' 相同,只是它使用 当前区域设置以插入适当的 数字分隔符。

这比其他答案更简单,并且避免了我原始答案中的浮点精度问题(保留在下面):

>>> import locale
>>> from decimal import Decimal
>>> 
>>> def f(d):
...     return '{0:n}'.format(d)
... 
>>> 
>>> locale.setlocale(locale.LC_ALL, 'en_us')
'en_us'
>>> print f(Decimal('5000.00'))
5,000.00
>>> print f(Decimal('1234567.000000'))
1,234,567.000000
>>> print f(Decimal('123456700000000.123'))
123,456,700,000,000.123
>>> locale.setlocale(locale.LC_ALL, 'no_no')
'no_no'
>>> print f(Decimal('5000.00'))
5.000,00
>>> print f(Decimal('1234567.000000'))
1.234.567,000000
>>> print f(Decimal('123456700000000.123'))
123.456.700.000.000,123

原来的错误答案

您可以告诉格式字符串使用与小数本身一样多的精度,并使用语言环境格式化程序:

def locale_format(d):
    return locale.format('%%0.%df' % (-d.as_tuple().exponent), d, grouping=True)

请注意,如果您有一个与实数相对应的小数,则该方法有效,但如果小数为 NaN+Inf 或类似的值,则无法正常工作。如果您的输入中有这些可能性,您需要在格式方法中考虑它们。

>>> locale.setlocale(locale.LC_ALL, 'en_US')
'en_US'
>>> locale_format(Decimal('1234567.000000'))
'1,234,567.000000'
>>> locale_format(Decimal('5000.00'))
'5,000.00'
>>> locale.setlocale(locale.LC_ALL, 'no_no')
'no_no'
>>> locale_format(Decimal('1234567.000000'))
'1.234.567,000000'
>>> locale_format(Decimal('5000.00'))
'5.000,00'
>>> locale_format(Decimal('NaN'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in locale_format
TypeError: bad operand type for unary -: 'str'

【讨论】:

  • 这对问题中的两个示例都给出了错误的答案。
  • 添加grouping=True会根据问题中的示例生成正确答案[已编辑答案以修复]。不幸的是,这并没有解决上面提到的 unutbu 的浮点精度问题。
  • @ChrisMartin:我添加了一个我认为可以解决所有问题的解决方案,使用 :n 表示类型。
  • 哇,太棒了:) 你也可以使用f = '{:n}'.format
  • 使用就够了:locale.setlocale(locale.LC_NUMERIC, 'en_US')
【解决方案2】:

使用 Python 3.5+ 的现代 Python 方法是:

>>> import locale
>>> locale.setlocale(locale.LC_NUMERIC, "de_DE")
>>> f'{Decimal("5000.00"):n}'
'5.000,00'
>>> locale.setlocale(locale.LC_NUMERIC, "en_US")
'en_US'
>>> f'{Decimal("5000.00"):n}'
'5,000.00'

F 字符串支持高级格式。因此,不需要额外的f 函数。 Babel for Python 会给你更多的方便:

>>> from babel import numbers
>>> numbers.format_decimal(.2345, locale='en_US')
'0.234'
>>> numbers.format_decimal(.2345, locale='de_DE')
'0,234'
 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-11
    • 1970-01-01
    • 2016-03-29
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多