The Looseleaf Papers

An undocumented argument in Python’s locale.atof function

Created

Modified

Published

Suppose we have a string like this:

>>> mystr = '1,200.30'

and we want to parse it into a number, following the locale rules for the meaning of periods and commas. Well, one option is to use the locale package to turn it into a float.

>>> import locale
>>> locale.setlocale(locale.LC_NUMERIC, '')
'en_US.UTF-8'
>>> locale.atof('1,200.30')
1200.3

However, if these numbers represent currency, we don’t want a float, we want a Decimal. But how do we get it? We can’t use the string directly:

>>> decimal.Decimal('1,200.30')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]

and if we try to convert it to a float first, we get rounding error:

>>> import decimal
>>> decimal.Decimal(locale.atof('1,200.30'))
Decimal('1200.299999999999954525264911353588104248046875')

It turns out, though, that locale.atof takes a func parameter. Here it is in Python 3:

def atof(string, func=float):
    "Parses a string as a float according to the locale settings."
    return func(delocalize(string))

and here it is in Python 2:

def atof(string, func=float):
    "Parses a string as a float according to the locale settings."
    #First, get rid of the grouping
    ts = localeconv()['thousands_sep']
    if ts:
        string = string.replace(ts, '')
    #next, replace the decimal point with a dot
    dd = localeconv()['decimal_point']
    if dd:
        string = string.replace(dd, '.')
    #finally, parse the string
    return func(string)

So we can just do this:

>>> locale.setlocale(locale.LC_NUMERIC, '')
'en_US.UTF-8'
>>> locale.atof('1,200.30', func=decimal.Decimal)
Decimal('1200.30')

It’s not in the official documentation, though.

locale.atof( string )

Converts a string to a floating point number, following the LC_NUMERIC settings.

https://docs.python.org/3/library/locale.html#locale.atof

This undocumented parameter is well-known, but even after Python 3 it does not seem to be documented yet.

Notice the undocumented argument for the result type:

>>> locale.atof('1,234', decimal.Decimal)
Decimal('1234')
>>> locale.atof('1,234', fractions.Fraction)
Fraction(1234, 1)

I’d advise writing your own function instead of relying on an undocumented argument.

—eryksun, June 26, 2013

https://mail.python.org/pipermail/tutor/2013-June/096421.html

I’m not sure I agree with that. I think it might be better to try to persuade the Python maintainers to document this excellent little feature.

Addendum 2026-01-23: it’s documented now.

locale.atof( string, func=float )

Converts a string to a number, following the LC_NUMERIC settings, by calling func on the result of calling delocalize() on string.

https://docs.python.org/3/library/locale.html#locale.atof

The commit pull request commit was from May 27, 2020, and the commit that added to the repo was April 2, 2022.

https://github.com/python/cpython/commit/208da6d508bb2683732151f4ae288dfc8001267c

https://github.com/python/cpython/pull/18183/commits/b61a38e81f132e01b19ee1c5086f678e0172234e