This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: str.format() :n integer output
Type: enhancement Stage:
Components: Interpreter Core Versions: Python 3.0, Python 2.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: eric.smith, mark, mark.dickinson
Priority: normal Keywords:

Created on 2008-05-09 14:08 by mark, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (9)
msg66471 - (view) Author: Mark Summerfield (mark) * Date: 2008-05-09 14:07
In Py30a5 the 'n' format option is not v. useful for integers:

>>> for x in range(8):
	print("{0:n} ".format(10**x), end="")
	
1 10 100 1,000 10,000 100,000 1e+06 1e+07

This is because it behaves like g once a number grows large. That makes
sense for floats, but since Python has unlimited size integers there is
currently no built-in way to get, 10**6 to output as 1,000,000 (or using
whatever the user's locale-dependent separator is). (It is easy to write
a suitable function for this, but it just seems that n is a bit of a
teaser in this regard.)

I think that n should stay the same for floats, but for integers should
never switch to g, but just use as many separators as needed.
msg66472 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2008-05-09 14:23
> I think that n should stay the same for floats, but for integers should
> never switch to g, but just use as many separators as needed.

I agree with this, in principle.  It might be some work to implement, 
though:  for floats, Python gets to use the OS-supplied formatting 
functions.  Indeed, it looks as though all that happens here is that the 
integer is converted to a float before formatting:

>>> print("{0:n} ".format(10**400), end="")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C double

For integers, we'd have to roll our own code. I had similar problems 
trying to implement the 'n' format code for Decimal;  in the end I just 
gave up and left it unimplemented.  Maybe using 'n' for an integer should 
just raise an exception, for now?

Eric, what do you think?
msg66474 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2008-05-09 14:42
The reason for this is that 'n' is defined in PEP 3101 as being a float
format only, and the rule is that if an integer sees a float format, it
does a float conversion and then prints the float with the supplied format.

I'd be okay with adding 'n' as an integer format, with the loose
definition of "just like 'd', but adding thousands separators".

As to the implementation, the OS supplied float formatting does not add
thousands separators.  I added the function add_thousands_grouping() to
Python/pystrtod.c in order implement this for floats.  It would be easy
to make this same code work for integers (and in fact it might already
work, although there are probably memory allocation issues to deal with).

Maybe we should bring up modifying the PEP on python-dev or python-3000.

This issue exists in 2.6 as well.
msg66475 - (view) Author: Mark Summerfield (mark) * Date: 2008-05-09 14:44
On 2008-05-09, Mark Dickinson wrote:
> Mark Dickinson <dickinsm@gmail.com> added the comment:
> > I think that n should stay the same for floats, but for integers should
> > never switch to g, but just use as many separators as needed.
>
> I agree with this, in principle.  It might be some work to implement,
> though:  for floats, Python gets to use the OS-supplied formatting
> functions.  Indeed, it looks as though all that happens here is that the
>
> integer is converted to a float before formatting:
> >>> print("{0:n} ".format(10**400), end="")
>
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> OverflowError: Python int too large to convert to C double
>
> For integers, we'd have to roll our own code. I had similar problems
> trying to implement the 'n' format code for Decimal;  in the end I just
> gave up and left it unimplemented.  Maybe using 'n' for an integer should
> just raise an exception, for now?
>
> Eric, what do you think?

It isn't hard (in Python):

import locale
locale.setlocale(locale.LC_ALL, "")
separator = locale.localeconv()["thousands_sep"]

def n_format(integer, separator):
    chars = []
    for i, char in enumerate(reversed("{0:d}".format(integer))):
        if i and not i % 3:
            chars.insert(0, separator)
        chars.insert(0, char)
    return "".join(chars)
msg66477 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2008-05-09 14:55
> It isn't hard (in Python):

<code deleted>

It's more complex, because the "3" is locale dependent, and is allowed
to be something like "3, then 2, then 3, then 1, repeating until the
start of the string".

See _group() in Lib/locale.py.

In any event, the code needs to be in C (sadly).  But as I said in my
previous comment (which probably crossed paths with yours), this C code
already exists.
msg66478 - (view) Author: Mark Summerfield (mark) * Date: 2008-05-09 14:55
On 2008-05-09, Eric Smith wrote:
> Eric Smith <eric@trueblade.com> added the comment:
>
> The reason for this is that 'n' is defined in PEP 3101 as being a float
> format only, and the rule is that if an integer sees a float format, it
> does a float conversion and then prints the float with the supplied format.
>
> I'd be okay with adding 'n' as an integer format, with the loose
> definition of "just like 'd', but adding thousands separators".
>
> As to the implementation, the OS supplied float formatting does not add
> thousands separators.  I added the function add_thousands_grouping() to
> Python/pystrtod.c in order implement this for floats.  It would be easy
> to make this same code work for integers (and in fact it might already
> work, although there are probably memory allocation issues to deal with).
>
> Maybe we should bring up modifying the PEP on python-dev or python-3000.

I hope that you do:-)

> This issue exists in 2.6 as well.
>
> ----------
> components: +Interpreter Core
> versions: +Python 2.6
>
> __________________________________
> Tracker <report@bugs.python.org>
> <http://bugs.python.org/issue2802>
> __________________________________
msg66479 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2008-05-09 15:12
> As to the implementation, the OS supplied float formatting does not add
> thousands separators.  I added the function add_thousands_grouping() to
> Python/pystrtod.c in order implement this for floats.

Excellent!  I didn't realise this code was already there.  Maybe there's 
also some way to use it to implement 'n' formatting for Decimal (which in 
some ways behaves like a hybrid floating-point and integer type).

I can't think of any reason that the LC_NUMERIC stuff shouldn't apply to 
integers as well as floats.
msg66659 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2008-05-11 19:53
Implemented in 2.6 as r63078.  I'll port this to py3k shortly.
msg66671 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2008-05-11 21:17
Implemented in 3.0 as r63093.  I'm closing this issue.

I added the C code that does the grouping insertion as
_PyString_InsertThousandsGrouping and _PyUnicode_InsertThousandsGrouping
(in 3.0).  This might be useful to others, although the API is fairly
complicated.

Mark Dickinson: For Decimal, you can probably get what you need from
Lib/locale.py, although the function _group() is private.
History
Date User Action Args
2022-04-11 14:56:34adminsetgithub: 47051
2008-05-11 21:17:56eric.smithsetstatus: open -> closed
resolution: fixed
messages: + msg66671
2008-05-11 19:53:57eric.smithsetmessages: + msg66659
2008-05-09 15:12:02mark.dickinsonsetmessages: + msg66479
2008-05-09 14:55:33marksetmessages: + msg66478
2008-05-09 14:55:01eric.smithsetmessages: + msg66477
2008-05-09 14:44:15marksetmessages: + msg66475
2008-05-09 14:42:20eric.smithsetmessages: + msg66474
components: + Interpreter Core
versions: + Python 2.6
2008-05-09 14:23:28mark.dickinsonsetpriority: normal
assignee: eric.smith
messages: + msg66472
nosy: + mark.dickinson, eric.smith
2008-05-09 14:08:07markcreate