By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,434 Members | 1,820 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,434 IT Pros & Developers. It's quick & easy.

Number Format function

P: n/a
I'm am relatively new to Python but use it daily. Today, I went looking
for a function, like PHP's number_function, that will take a number and
return a string with number formatted with grouped thousands and the
decimal portion rounded to a given number of places. This is certainly
needed when you want to take a floating-point value from a database and
display it as currency, for instance. I could not find what I was
looking for so I wrote the following function. I hope either (a) I've
provided something useful or (b) someone can tell me what I *should*
have done! Thanks.

import math

def number_format(num, places=0):
"""Format a number with grouped thousands and given decimal places"""

#is_negative = (num < 0)
#if is_negative:
# num = -num

places = max(0,places)
tmp = "%.*f" % (places, num)
point = tmp.find(".")
integer = (point == -1) and tmp or tmp[:point]
decimal = (point != -1) and tmp[point:] or ""

count = commas = 0
formatted = []
for i in range(len(integer) - 1, 0, -1):
count += 1
formatted.append(integer[i])
if count % 3 == 0:
formatted.append(",")

integer = "".join(formatted[::-1])
return integer+decimal

Feb 8 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Your code has a little bug, I highly recommend to add a test to your
code, for an idea see below - I fixed your code as well.

#!/usr/bin/env python
import math

def number_format(num, places=0):
"""Format a number with grouped thousands and given decimal
places"""
#is_negative = (num < 0)
#if is_negative:
# num = -num

places = max(0,places)
tmp = "%.*f" % (places, num)
point = tmp.find(".")
integer = (point == -1) and tmp or tmp[:point]
decimal = (point != -1) and tmp[point:] or ""

count = commas = 0
formatted = []
for i in range(len(integer) - 1, 0, -1):
count += 1
formatted.append(integer[i])
if count % 3 == 0:
formatted.append(",")
formatted.append(integer[0]) # this misses in your part
integer = "".join(formatted[::-1])
return integer+decimal
#
# add something like this: it helps to prevent you break your code
#
import unittest

class test_number_format(unittest.TestCase):
def test(self):
self.assertEqual(number_format(1000000, 2), '1,000,000.00')
self.assertEqual(number_format(100000, 2), '100,000.00')
self.assertEqual(number_format(100, 2), '100.00')
self.assertEqual(number_format(1000000.33, 2), '1,000,000.33')
self.assertEqual(number_format(1000000.333, 2), '1,000,000.33')
self.assertEqual(number_format(1000000.3, 2), '1,000,000.30')
self.assertEqual(number_format(123456, 2), '123,456.00')
self.assertEqual(number_format(12345, 2), '12,345.00')
self.assertEqual(number_format(123, 2), '123.00')
self.assertEqual(number_format(123456.33, 2), '123,456.33')
self.assertEqual(number_format(12345.333, 2), '12,345.33')
self.assertEqual(number_format(123.3, 2), '123.30')

suite = unittest.makeSuite(test_number_format)
unittest.TextTestRunner(verbosity=2).run(suite)

Feb 8 '06 #2

P: n/a
Thanks. I noticed the bugs later. But after talking with my boss, he
suggested something more elegant (again *untested*, yet):

import locale

def number_format(num, places=0)
"""Format a number according to locality and given places"""
locale.setlocale(locale.LC_ALL, locale.getdefaultlocale()[0])
return locale.format("%.*f", (places, num), 1)

wi******@hotmail.com wrote:
Your code has a little bug, I highly recommend to add a test to your
code, for an idea see below - I fixed your code as well.

#!/usr/bin/env python
import math

def number_format(num, places=0):
"""Format a number with grouped thousands and given decimal
places"""
#is_negative = (num < 0)
#if is_negative:
# num = -num

places = max(0,places)
tmp = "%.*f" % (places, num)
point = tmp.find(".")
integer = (point == -1) and tmp or tmp[:point]
decimal = (point != -1) and tmp[point:] or ""

count = commas = 0
formatted = []
for i in range(len(integer) - 1, 0, -1):
count += 1
formatted.append(integer[i])
if count % 3 == 0:
formatted.append(",")
formatted.append(integer[0]) # this misses in your part
integer = "".join(formatted[::-1])
return integer+decimal
#
# add something like this: it helps to prevent you break your code
#
import unittest

class test_number_format(unittest.TestCase):
def test(self):
self.assertEqual(number_format(1000000, 2), '1,000,000.00')
self.assertEqual(number_format(100000, 2), '100,000.00')
self.assertEqual(number_format(100, 2), '100.00')
self.assertEqual(number_format(1000000.33, 2), '1,000,000.33')
self.assertEqual(number_format(1000000.333, 2), '1,000,000.33')
self.assertEqual(number_format(1000000.3, 2), '1,000,000.30')
self.assertEqual(number_format(123456, 2), '123,456.00')
self.assertEqual(number_format(12345, 2), '12,345.00')
self.assertEqual(number_format(123, 2), '123.00')
self.assertEqual(number_format(123456.33, 2), '123,456.33')
self.assertEqual(number_format(12345.333, 2), '12,345.33')
self.assertEqual(number_format(123.3, 2), '123.30')

suite = unittest.makeSuite(test_number_format)
unittest.TextTestRunner(verbosity=2).run(suite)


Feb 8 '06 #3

P: n/a
This is a little faster:

def number_format(num, places=0):
"""Format a number according to locality and given places"""
locale.setlocale(locale.LC_ALL, "")
return locale.format("%.*f", (places, num), True)

I tested this ok with my test

Feb 8 '06 #4

P: n/a
"wi******@hotmail.com" <ma**********@gmail.com> wrote in
news:11**********************@f14g2000cwb.googlegr oups.com:
def number_format(num, places=0):
"""Format a number according to locality and given places"""
locale.setlocale(locale.LC_ALL, "")
return locale.format("%.*f", (places, num), True)


There are some edge cases in the format conversion that could present
some issues. For example:
print number_format( 2312753.44500000, 2 ) 2,312,753.44 print number_format( 2312753.44500001, 2 )

2,312,753.45

I would expect the first to produce the same results as the second, but,
I suppose because of one of floating point's features, it doesn't work
that way.

--
rzed
Feb 8 '06 #5

P: n/a
Rick Zantow <rz*****@gmail.com> wrote:
print number_format( 2312753.44500000, 2 )2,312,753.44 print number_format( 2312753.44500001, 2 )2,312,753.45

I would expect the first to produce the same results as the second, but,
I suppose because of one of floating point's features, it doesn't work
that way.

2312753.44500000 2312753.4449999998 2312753.44500001

2312753.4450000101

So, yeah, the nature of floating points is going to make that
first one round "unexpectedly".

--
\S -- si***@chiark.greenend.org.uk -- http://www.chaos.org.uk/~sion/
___ | "Frankly I have no feelings towards penguins one way or the other"
\X/ | -- Arthur C. Clarke
her nu becomež se bera eadward ofdun hlęddre heafdes bęce bump bump bump
Feb 9 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.