views:

1668

answers:

6

I am trying to print an integer in Python 2.6.1 with commas as thousands separators. For example, I want to show the number 1234567 as "1,234,567". How would I go about doing this? I have seen many examples on Google, but I am looking for the simplest practical way.

It does not need to be locale-specific to decide between periods and commas. I would prefer something as simple as reasonably possible.

+4  A: 

I'm sure there must be a standard library function for this, but it was fun to try to write it myself using recursion so here's what I came up with:

def intToStringWithCommas(x):
    if type(x) is not int and type(x) is not long:
        raise TypeError("Not an integer!")
    if x < 0:
        return '-' + intToStringWithCommas(-x)
    elif x < 1000:
        return str(x)
    else:
        return intToStringWithCommas(x / 1000) + ',' + '%03d' % (x % 1000)

Having said that, if someone else does find a standard way to do it, you should use that instead.

Mark Byers
Unfortunately doesn't work in all cases. intToStringWithCommas(1000.1) -> '1.0001,000'
Nadia Alramli
He specifically said integers and that it should be as simple as possible, so I decided not to handle datatypes other than integers. I also made it explicit in the function name _int_ToStringWithCommas. Now I've also added a raise to make it more clear.
Mark Byers
You are right, discard my comment
Nadia Alramli
No worries! Having the extra input check is a good practice anyway.
Mark Byers
+12  A: 

I got this to work:

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'en_US')
'en_US'
>>> locale.format("%d", 1255000, grouping=True)
'1,255,000'

Sure, you don't need internationalization support, but it's clear, concise, and uses a built-in library.

P.S. That "%d" is the usual %-style formatter. You can have only one formatter, but it can be whatever you need in terms of field width and precision settings.

P.P.S. If you can't get locale to work, I'd suggest a modified version of Mark's answer:

def intWithCommas(x):
    if type(x) not in [type(0), type(0L)]:
        raise TypeError("Parameter must be an integer.")
    if x < 0:
        return '-' + intWithCommas(-x)
    result = ''
    while x >= 1000:
        x, r = divmod(x, 1000)
        result = ",%03d%s" % (r, result)
    return "%d%s" % (x, result)

Recursion is useful for the negative case, but one recursion per comma seems a bit excessive to me.

Mike DeSimone
I tried your code, and unfortunately, I get this: "locale.Error: unsupported locale setting". :-s
Mark Byers
I've always thought of using the locale library as non-intuitive and somewhat complex. Every time I need to use it, I have to look it up. I can't remember how to do it off the top of my head.
mikez302
Mark: If you're on Linux, you might want to look at what is in your /etc/locale.gen, or whatever your glibc is using to build its locales. You might also want to try ""en", "en_US.utf8", "en_US.UTF-8", 'en_UK" (sp?), etc.mikez: There needs to be a book: "Dr. PEP: Or How I Learned to Stop Worrying and Love docs.python.org." I gave up memorizing all the libraries back around Python 1.5.6. As for `locale`, I use as little of it as I can.
Mike DeSimone
You can use '' for `setlocale` to use the default, which hopefully will be appropriate.
Mark Ransom
Try this: locale.setlocale(locale.LC_ALL, '') It worked for me
Nadia Alramli
Mike: This is not on Linux. I tried it in both Windows Vista, and Cygwin.
Mark Byers
I tried "locale.setlocale(locale.LC_ALL, '')" but it gave "1.255.000" instead of "1,255,000". :( How do I get the missing locales for Windows Vista?
Mark Byers
Sorry, Windows is outside my experience, and though I use Cygwin, I don't know how it handles locales.
Mike DeSimone
One advantage with doing it the simple way (like in my answer, and some others here) is that it is a) fully cross platform b) it does what the submitter wants regardless of the locale of the computer c) it doesn't depend on things that most people have never used before and that most people don't properly understand. This solution doesn't meet any of those requirements. Having said that, I think there is room on StackOverflow for both types of solution.
Mark Byers
Yeah, I think I remember some guy named Wall saying something about problems with multiple solutions. ^_- Answer amended.
Mike DeSimone
+2  A: 

Just subclass long (or float, or whatever). This is highly practical, because this way you can still use your numbers in math ops (and therefore existing code), but they will all print nicely in your terminal.

>>> class number(long):

        def __init__(self, value):
            self = value

        def __repr__(self):
            s = str(self)
            l = [x for x in s if x in '1234567890']
            for x in reversed(range(len(s)-1)[::3]):
                l.insert(-x, ',')
            l = ''.join(l[1:])
            return ('-'+l if self < 0 else l) 

>>> number(-100000)
-100,000
>>> number(-100)
-100
>>> number(-12345)
-12,345
>>> number(928374)
928,374
>>> 345
twneale
>>> number(-100) -> "-,100"
Mark Byers
Fixed it. See new examples
twneale
I like the subclass idea, but is `__repr__()` the correct method to override? I would suggest overriding `__str__()` and leaving `__repr__()` alone, because `int(repr(number(928374)))` ought to work, but `int()` will choke on the commas.
steveha
@steveha has a good point, but the justification should have been that `number(repr(number(928374)))` doesn't work, not `int(repr(number(928374)))`. All the same, to make this approach work directly with `print`, as the OP requested, the `__str__()` method should be the one overridden rather than `__repr__()`. Regardless, there appears to be a bug in the core comma insertion logic.
martineau
+8  A: 

Here is the locale grouping code after removing irrelevant parts and cleaning it up a little:

(The following only works for integers)

def group(number):
    s = '%d' % number
    groups = []
    while s and s[-1].isdigit():
        groups.append(s[-3:])
        s = s[:-3]
    return s + ','.join(reversed(groups))

>>> group(-23432432434.34)
'-23,432,432,434'


There are already some good answers in here. I just want to add this for future reference. In python 2.7 there is going to be a format specifier for thousands separator. According to python docs it works like this

>>> '{:20,.2}'.format(f)
'18,446,744,073,709,551,616.00'

In python3.1 you can do the same thing like this:

>>> format(1234567, ',d')
'1,234,567'
Nadia Alramli
Wow, thanks for the info. It's nice to know that this will be easier in future.
Mark Byers
+1  A: 

ok, but how to get number separated by dots?

how yes no
Maybe I don't understand, but it seems like you would just need to insert a dot instead of a comma. `locale` would automatically use the proper character as determined by calling its `locale.setlocale()` method.
martineau