Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

str.format() :n integer output #47051

Closed
mark-summerfield mannequin opened this issue May 9, 2008 · 9 comments
Closed

str.format() :n integer output #47051

mark-summerfield mannequin opened this issue May 9, 2008 · 9 comments
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement

Comments

@mark-summerfield
Copy link
Mannequin

mark-summerfield mannequin commented May 9, 2008

BPO 2802
Nosy @mdickinson, @ericvsmith, @mark-summerfield

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = 'https://github.com/ericvsmith'
closed_at = <Date 2008-05-11.21:17:56.767>
created_at = <Date 2008-05-09.14:08:07.355>
labels = ['interpreter-core', 'type-feature']
title = 'str.format() :n integer output'
updated_at = <Date 2008-05-11.21:17:56.631>
user = 'https://github.com/mark-summerfield'

bugs.python.org fields:

activity = <Date 2008-05-11.21:17:56.631>
actor = 'eric.smith'
assignee = 'eric.smith'
closed = True
closed_date = <Date 2008-05-11.21:17:56.767>
closer = 'eric.smith'
components = ['Interpreter Core']
creation = <Date 2008-05-09.14:08:07.355>
creator = 'mark'
dependencies = []
files = []
hgrepos = []
issue_num = 2802
keywords = []
message_count = 9.0
messages = ['66471', '66472', '66474', '66475', '66477', '66478', '66479', '66659', '66671']
nosy_count = 3.0
nosy_names = ['mark.dickinson', 'eric.smith', 'mark']
pr_nums = []
priority = 'normal'
resolution = 'fixed'
stage = None
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue2802'
versions = ['Python 2.6', 'Python 3.0']

@mark-summerfield
Copy link
Mannequin Author

mark-summerfield mannequin commented May 9, 2008

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.

@mark-summerfield mark-summerfield mannequin added the type-feature A feature request or enhancement label May 9, 2008
@mdickinson
Copy link
Member

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?

@ericvsmith
Copy link
Member

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.

@ericvsmith ericvsmith added the interpreter-core (Objects, Python, Grammar, and Parser dirs) label May 9, 2008
@mark-summerfield
Copy link
Mannequin Author

mark-summerfield mannequin commented May 9, 2008

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)

@ericvsmith
Copy link
Member

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.

@mark-summerfield
Copy link
Mannequin Author

mark-summerfield mannequin commented May 9, 2008

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


@mdickinson
Copy link
Member

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.

@ericvsmith
Copy link
Member

Implemented in 2.6 as r63078. I'll port this to py3k shortly.

@ericvsmith
Copy link
Member

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.

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

2 participants