prePEP: Money data type

Alex Martelli aleax at aleax.it
Mon Oct 20 15:27:48 EDT 2003


Batista, Facundo wrote:

> #- As a side note, it's quite possible to spend inordinate
> #- amounts of attention on formatting.  I would suggest that
> #- a fundamental 'money' class should first of all nail down
> #- the *computation* issues (just that variety of rounding
> #- specs is gonna be SUCH a bear...!) and receiving and
> 
> It's very temptating to str() just represent the number, and if you want
> something else, overload it.
> 
> The problem is that decimalSeparator and thousandSeparator are important
> to parse the string in the constructor (if I need str() to give me a ','
> as decimal point, I also need to supply a ',' as decimal point to the
> constructor).

Hmmm, I see your point.  But, in general, parsing '1.000' would be
ambiguous -- is it one thousand with '.' as the thousandSeparator or
one in a currency which requires three decimal digits?

"In fact of ambiguity, refuse the temptation to guess" (do an
"import this" from interactive Python once in a while to remind
you...!-).  So, although it seems like a cool idea to infer the
decimal and thousand separators from strings you're given, I
suspect it might be better to avoid tackling that in the base
class -- said class, if it must parse strings, could use the
conventions specified for the purpose as per module locale, and
not attempt to guess (or infer) the conventions in use.  Module
locale, after all, DOES give a lot of presumably-relevant info:

>>> import locale
>>> locale.localeconv()
{'mon_decimal_point': '', 'int_frac_digits': 127, 'p_sep_by_space': 127,
'frac_digits': 127, 'thousands_sep': '', 'n_sign_posn': 127,
'decimal_point': '.', 'int_curr_symbol': '', 'n_cs_precedes': 127,
'p_sign_posn': 127, 'mon_thousands_sep': '', 'negative_sign': '',
'currency_symbol': '', 'n_sep_by_space': 127, 'mon_grouping': [],
'p_cs_precedes': 127, 'positive_sign': '', 'grouping': []}
>>> locale.setlocale(locale.LC_ALL,'')
'en_US'
>>> locale.localeconv()
{'mon_decimal_point': '.', 'int_frac_digits': 2, 'p_sep_by_space': 0,
'frac_digits': 2, 'thousands_sep': ',', 'n_sign_posn': 1, 'decimal_point':
'.', 'int_curr_symbol': 'USD ', 'n_cs_precedes': 1, 'p_sign_posn': 1,
'mon_thousands_sep': ',', 'negative_sign': '-', 'currency_symbol': '$',
'n_sep_by_space': 0, 'mon_grouping': [3, 3, 0], 'p_cs_precedes': 1,
'positive_sign': '', 'grouping': [3, 3, 0]}
>>>

See?  After I called setlocale to set it to the user locale (rather
than the neutral 'C' locale), 'en_US' in my case, I got lot of info
in the dict that locale.localeconv() returns: money decimal point is
'.', fractional-parts-digits are 2 for both base and internationalized
formatting, thousands separator is comma for both ordinary and money
amounts, the currency symbol is '$' in base use but 'USD' for fully
internationalized used, etc, etc.

I'm pretty sure you can find all details documented in many places,
although I would of course suggest "Python in a Nutshell" p.216-219
for very concise coverage of what I think is really useful here;-).

The base class Money seem to need just a few of these to be able to
parse strings (I would not use them for default output with either
repr or str, although maybe a non-special method such as 'format'
MIGHT, for the user's convenience, emit a string formatted by such
guidelines -- I'm neutral, say +0, on the latter).


Alex





More information about the Python-list mailing list