How can I locale-format a python Decimal and preserve its precision?

耗尽温柔 提交于 2020-12-29 05:22:25

问题


How can I format a Decimal using a locale?

To describe by examples, I'm trying to define a function f such that in the US English locale:

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

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

Some things that don't work:

  • f = str doesn't use locale; f(Decimal('5000.00')) == '5000.00'

  • f = lambda d: locale.format('%f', d) doesn't preserve the decimal precision; f(Decimal('5000.00')) == '5000.000000'

  • f = lambda d: locale.format('%.2f', d) uses a fixed precision, which isn't what I'm after; f(Decimal('1234567.000000')) == '1234567.00'


回答1:


Reading through the source for the decimal module, Decimal.__format__ provides full PEP 3101 support, and all you have to do is select the correct presentation type. In this case, you want the :n type. According PEP 3101 spec, this :n has the following properties:

'n' - Number. This is the same as 'g', except that it uses the current locale setting to insert the appropriate number separator characters.

This is simpler than other answers, and avoids the float precision issue in my original answer (preserved below):

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

Original, wrong answer

You can just tell the format string to use as much precision as is included in the decimal itself and use the locale formatter:

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

Note that works if you've got a decimal which corresponds to a real number, but doesn't work correctly if the decimal is NaN or +Inf or something like that. If those are possibilities in your input, you'd need to account for them in the format method.

>>> 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'


来源:https://stackoverflow.com/questions/31910741/how-can-i-locale-format-a-python-decimal-and-preserve-its-precision

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!