# Manually formatting numbers in Python

I was working on a little Python challenge that was a bit more difficult than expected: format any non-negative number so 1000 turns into "1,000" , 10000000 into "10,000,000" and so forth. I managed to do it, but I find my solution not very readable:

def formatting(n):
m = str(n)  # Turn it into string
m2 = []  # Empty list that will have the split version of the final number
for i in range(0,len(m),3):  # Iterate every three elements

m2.append(m[::-1][i:i+3][::-1])  # Append last three numbers, second to last three numbers, etc.
m2.append(',')  # Add a comma between loops
m3 = ''.join(m2[::-1])[1:] # Join and drop the first element which is always a comma.
return m3


This works but it isn't as nice as it could be. What can be done?

• Shouldn't m = str(m) be m = str(n)? Sep 24 '19 at 19:39
• You're right! My code wasn't in function form so I had a little typo when I adapted it Sep 24 '19 at 19:44

A few points:

• Reversing the string m multiple times is unnecessary. Slicing can be done on the original string using correct indices. m[::-1][i:i+3][::-1] is equivalent to m[-i-3:len(m)-i]. Another approach is to traverse the indices in the reverse order for i in range(len(m)-1, -1, -3) and then perform slicing accordingly.

• The logic can be simplified using str.join. m2.append(',') can be omitted. And you can just do

m3 = ','.join(m2[::-1])

• Further improvements can be achieved by using list comprehensions and traversing the string from the beginning rather than in the reverse order. Some calculation for the indices are needed:

def formatting(n):
m = str(n)  # Turn it into string
num_digits = len(m)
seg1_len = (num_digits % 3) or 3  # Calculate length of the first segment
segments = [m[:seg1_len], *(m[i:i+3] for i in range(seg1_len, num_digits, 3))]
return ','.join(segments)

• Python 3's built-in formatting specification actually supports the thousands separator. So you can just do this to achieve the same functionality:

formatted_n = f"{n:,}"


Or equivalently:

formatted_n = "{:,}".format(n)

• Thanks! That was quite insightful! Also didn't know about that formatting option. Would have saved me of using locale multiple times. Sep 24 '19 at 20:25
• I'm not sure what you used locale for. According to the doc, For a locale aware separator, use the 'n' integer presentation type instead.
– GZ0
Sep 24 '19 at 20:28
• When I'm working with money data that I have to format in some specific currency, but that's totally outside the scope of this Sep 24 '19 at 20:45