Pregunta

Estoy tratando de imprimir un número entero en Python 2.6.1 con comas como miles de separadores. Por ejemplo, quiero mostrar el número 1234567 como 1,234,567. ¿Cómo haría para hacer esto? He visto muchos ejemplos en Google, pero estoy buscando la forma práctica más simple.

No es necesario que sea específico de la localidad para decidir entre puntos y comas. Preferiría algo tan simple como sea razonablemente posible.

¿Fue útil?

Solución

Configuración regional desconocida

'{:,}'.format(value)  # For Python ≥2.7
f'{value:,}'  # For Python ≥3.7

Configuración regional

import locale
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')  # Customize

'{:n}'.format(value)  # For Python ≥2.7
f'{value:n}'  # For Python ≥3.7

Referencia

Por Especificación de formato Mini-idioma ,

  

La opción ',' señala el uso de una coma para un separador de miles. Para un separador de configuración regional, use el 'n' tipo de presentación entera en su lugar.

Otros consejos

Tengo esto para trabajar:

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

Claro, no necesita soporte de internacionalización, pero es claro, conciso y utiliza una biblioteca integrada.

P.S. Que & Quot;% d & Quot; es el formateador de estilo% habitual. Solo puede tener un formateador, pero puede ser lo que necesite en términos de ancho de campo y configuración de precisión.

P.P.S. Si no puede hacer que locale funcione, le sugiero una versión modificada de la respuesta de Mark:

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)

La recursión es útil para el caso negativo, pero una recurrencia por coma me parece un poco excesiva.

Por ineficiencia e ilegibilidad es difícil de superar:

>>> import itertools
>>> s = '-1234567'
>>> ','.join(["%s%s%s" % (x[0], x[1] or '', x[2] or '') for x in itertools.izip_longest(s[::-1][::3], s[::-1][1::3], s[::-1][2::3])])[::-1].replace('-,','-')

Aquí está el código de agrupación local después de eliminar partes irrelevantes y limpiarlo un poco:

(Lo siguiente solo funciona para enteros)

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'

Ya hay algunas buenas respuestas aquí. Solo quiero agregar esto para referencia futura. En python 2.7 habrá un especificador de formato para el separador de miles. De acuerdo con python docs funciona así

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

En python3.1 puede hacer lo mismo de esta manera:

>>> format(1234567, ',d')
'1,234,567'

Me sorprende que nadie haya mencionado que puedes hacer esto con f-strings en Python 3.6 tan fácil como esto:

>>> num = 10000000
>>> print(f"{num:,d}")
10,000,000

... donde la parte después de los dos puntos es el especificador de formato. La coma es el carácter separador que desea, por lo que f"{num:_d}" usa guiones bajos en lugar de una coma.

Esto es equivalente a usar format(num, ",d") para versiones anteriores de python 3.

Aquí hay un reemplazo de expresiones regulares de una línea:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)

Funciona solo para salidas no completas:

import re
val = 1234567890
re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%d" % val)
# Returns: '1,234,567,890'

val = 1234567890.1234567890
# Returns: '1,234,567,890'

O para flotantes con menos de 4 dígitos, cambie el especificador de formato a %.3f:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.3f" % val)
# Returns: '1,234,567,890.123'

NB: no funciona correctamente con más de tres dígitos decimales, ya que intentará agrupar la parte decimal:

re.sub("(\d)(?=(\d{3})+(?!\d))", r"\1,", "%.5f" % val)
# Returns: '1,234,567,890.12,346'

Cómo funciona

Vamos a desglosarlo:

re.sub(pattern, repl, string)

pattern = \
    "(\d)           # Find one digit...
     (?=            # that is followed by...
         (\d{3})+   # one or more groups of three digits...
         (?!\d)     # which are not followed by any more digits.
     )",

repl = \
    r"\1,",         # Replace that one digit by itself, followed by a comma,
                    # and continue looking for more matches later in the string.
                    # (re.sub() replaces all matches it finds in the input)

string = \
    "%d" % val      # Format the string as a decimal to begin with

Esto es lo que hago para las carrozas. Aunque, sinceramente, no estoy seguro de para qué versiones funciona, estoy usando 2.7:

my_number = 4385893.382939491

my_string = '{:0,.2f}'.format(my_number)

Devoluciones: 4,385,893.38

Actualización: Recientemente tuve un problema con este formato (no podía decirle el motivo exacto), pero pude solucionarlo al soltar el 0:

my_string = '{:,.2f}'.format(my_number)

También puede usar '{:n}'.format( value ) para una representación regional. Creo que esta es la forma más sencilla de una solución de configuración regional.

Para obtener más información, busque thousands en Python DOC .

Para la moneda, puede usar locale.currency, configurando la bandera grouping:

Código

import locale

locale.setlocale( locale.LC_ALL, '' )
locale.currency( 1234567.89, grouping = True )

Salida

'Portuguese_Brazil.1252'
'R$ 1.234.567,89'

Estoy seguro de que debe haber una función de biblioteca estándar para esto, pero fue divertido intentar escribirlo yo mismo usando la recursión, así que esto es lo que se me ocurrió:

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)

Habiendo dicho eso, si alguien más encuentra una forma estándar de hacerlo, deberías usar eso en su lugar.

Del comentarios para activar la receta del estado 498181 Reformé esto:

import re
def thous(x, sep=',', dot='.'):
    num, _, frac = str(x).partition(dot)
    num = re.sub(r'(\d{3})(?=\d)', r'\1'+sep, num[::-1])[::-1]
    if frac:
        num += dot + frac
    return num

Utiliza la función de expresiones regulares: lookahead es decir, (?=\d) para asegurarse de que solo los grupos de tres dígitos que tienen un dígito 'después' obtengan una coma. Digo 'después' porque la cadena es inversa en este punto.

[::-1] simplemente invierte una cadena.

Ampliando ligeramente la respuesta de Ian Schneider:

Si desea utilizar un separador de miles personalizado, la solución más simple es:

'{:,}'.format(value).replace(',', your_custom_thousands_separator)

Ejemplos

'{:,.2f}'.format(123456789.012345).replace(',', ' ')

Si quieres una representación alemana como esta, se vuelve un poco más complicada:

('{:,.2f}'.format(123456789.012345)
          .replace(',', ' ')  # 'save' the thousands separators 
          .replace('.', ',')  # dot to comma
          .replace(' ', '.')) # thousand separators to dot

Python 3

-

Enteros (sin decimal):

"{:,d}".format(1234567)

-

Flotadores (con decimal):

"{:,.2f}".format(1234567)

donde el número antes de f especifica el número de lugares decimales.

-

Bonus

Función de arranque rápido y sucio para el sistema de numeración indio lakhs / crores (12,34,567):

https://stackoverflow.com/a/44832241/4928578

La respuesta aceptada está bien, pero en realidad prefiero format(number,','). Más fácil para mí interpretar y recordar.

https://docs.python.org/3/library/functions. formato html #

desde Python versión 2.6 puede hacer esto:

def format_builtin(n):
    return format(n, ',')

Para las versiones de Python < 2.6 y solo para su información, aquí hay 2 soluciones manuales, convierten los flotantes en int pero los números negativos funcionan correctamente:

def format_number_using_lists(number):
    string = '%d' % number
    result_list = list(string)
    indexes = range(len(string))
    for index in indexes[::-3][1:]:
        if result_list[index] != '-':
            result_list.insert(index+1, ',')
    return ''.join(result_list)

algunas cosas para notar aquí:

  • esta línea: string = '% d'% number convierte bellamente un número en una cadena, admite negativos y elimina fracciones de flotadores, convirtiéndolos en ints;
  • este segmento indexa [:: - 3] devuelve cada tercer elemento a partir de al final, así que usé otro segmento [1:] para eliminar el último elemento porque no necesito una coma después del último número;
  • este condicional si l [index]! = '-' se utiliza para admitir números negativos, no inserte una coma después del signo menos.

Y una versión más hardcore:

def format_number_using_generators_and_list_comprehensions(number):
    string = '%d' % number
    generator = reversed( 
        [
            value+',' if (index!=0 and value!='-' and index%3==0) else value
            for index,value in enumerate(reversed(string))
        ]
    )
    return ''.join(generator)

Aquí hay uno que también funciona para carrozas:

def float2comma(f):
    s = str(abs(f)) # Convert to a string
    decimalposition = s.find(".") # Look for decimal point
    if decimalposition == -1:
        decimalposition = len(s) # If no decimal, then just work from the end
    out = "" 
    for i in range(decimalposition+1, len(s)): # do the decimal
        if not (i-decimalposition-1) % 3 and i-decimalposition-1: out = out+","
        out = out+s[i]      
    if len(out):
        out = "."+out # add the decimal point if necessary
    for i in range(decimalposition-1,-1,-1): # working backwards from decimal point
        if not (decimalposition-i-1) % 3 and decimalposition-i-1: out = ","+out
        out = s[i]+out      
    if f < 0:
        out = "-"+out
    return out

Ejemplo de uso:

>>> float2comma(10000.1111)
'10,000.111,1'
>>> float2comma(656565.122)
'656,565.122'
>>> float2comma(-656565.122)
'-656,565.122'

One liner para Python 2.5+ y Python 3 (solo int positivo):

''.join(reversed([x + (',' if i and not i % 3 else '') for i, x in enumerate(reversed(str(1234567)))]))

Soy un principiante de Python, pero un programador experimentado. Tengo Python 3.5, así que puedo usar la coma, pero este es un ejercicio de programación interesante. Considere el caso de un entero sin signo. El programa Python más legible para agregar miles de separadores parece ser:

def add_commas(instr):
    out = [instr[0]]
    for i in range(1, len(instr)):
        if (len(instr) - i) % 3 == 0:
            out.append(',')
        out.append(instr[i])
    return ''.join(out)

También es posible utilizar una lista de comprensión:

add_commas(instr):
    rng = reversed(range(1, len(instr) + (len(instr) - 1)//3 + 1))
    out = [',' if j%4 == 0 else instr[-(j - j//4)] for j in rng]
    return ''.join(out)

Esto es más corto, y podría ser un trazador de líneas, pero tendrá que hacer algo de gimnasia mental para entender por qué funciona. En ambos casos obtenemos:

for i in range(1, 11):
    instr = '1234567890'[:i]
    print(instr, add_commas(instr))
1 1
12 12
123 123
1234 1,234
12345 12,345
123456 123,456
1234567 1,234,567
12345678 12,345,678
123456789 123,456,789
1234567890 1,234,567,890

La primera versión es la opción más sensata, si desea que se entienda el programa.

esto se cuece en python por PEP - > https://www.python.org/dev/peps/pep-0378/

solo use el formato (1000, ', d') para mostrar un número entero con separador de miles

hay más formatos descritos en el PEP, tenga

Esto hace dinero junto con las comas

def format_money(money, presym='$', postsym=''):
    fmt = '%0.2f' % money
    dot = string.find(fmt, '.')
    ret = []
    if money < 0 :
        ret.append('(')
        p0 = 1
    else :
        p0 = 0
    ret.append(presym)
    p1 = (dot-p0) % 3 + p0
    while True :
        ret.append(fmt[p0:p1])
        if p1 == dot : break
        ret.append(',')
        p0 = p1
        p1 += 3
    ret.append(fmt[dot:])   # decimals
    ret.append(postsym)
    if money < 0 : ret.append(')')
    return ''.join(ret)

Tengo una versión de python 2 y python 3 de este código. Sé que la pregunta se hizo para Python 2, pero ahora (8 años más tarde jaja) la gente probablemente usará Python 3.

Código Python 3:

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print('The original number is: {}. '.format(number))
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print('The new and improved number is: {}'.format(number))        


Código de Python 2: (Editar. El código de Python 2 no funciona. Creo que la sintaxis es diferente).

import random
number = str(random.randint(1, 10000000))
comma_placement = 4
print 'The original number is: %s.' % (number)
while True:
    if len(number) % 3 == 0:
        for i in range(0, len(number) // 3 - 1):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
            comma_placement = comma_placement + 4
    else:
        for i in range(0, len(number) // 3):
            number = number[0:len(number) - comma_placement + 1] + ',' + number[len(number) - comma_placement + 1:]
    break
print 'The new and improved number is: %s.' % (number) 

Estoy usando Python 2.5, así que no tengo acceso al formato incorporado.

Miré el código Django intcomma (intcomma_recurs en el código a continuación) y me di cuenta de que es ineficiente, porque es recursivo y también compilar la expresión regular en cada ejecución tampoco es algo bueno. Esto no es necesariamente un 'problema' ya que django no está realmente tan enfocado en este tipo de rendimiento de bajo nivel. Además, esperaba un factor de diferencia de 10 en el rendimiento, pero es solo 3 veces más lento.

Por curiosidad, implementé algunas versiones de intcomma para ver cuáles son las ventajas de rendimiento al usar regex. Los datos de mi prueba concluyen una ligera ventaja para esta tarea, pero sorprendentemente no mucho.

También me complació ver lo que sospechaba: el uso del enfoque de xrange inverso es innecesario en el caso sin regex, pero hace que el código se vea un poco mejor a costa de un rendimiento de ~ 10%.

Además, supongo que lo que estás pasando es una cadena y se parece a un número. Resultados indeterminados de lo contrario.

from __future__ import with_statement
from contextlib import contextmanager
import re,time

re_first_num = re.compile(r"\d")
def intcomma_noregex(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    segments,_from_index,leftover = [],0,(period-start_digit) % 3
    for _index in xrange(start_digit+3 if not leftover else start_digit+leftover,period,3):
        segments.append(value[_from_index:_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[_from_index:])
    return ','.join(segments)

def intcomma_noregex_reversed(value):
    end_offset, start_digit, period = len(value),re_first_num.search(value).start(),value.rfind('.')
    if period == -1:
        period=end_offset
    _from_index,segments = end_offset,[]
    for _index in xrange(period-3,start_digit,-3):
        segments.append(value[_index:_from_index])
        _from_index=_index
    if not segments:
        return value
    segments.append(value[:_from_index])
    return ','.join(reversed(segments))

re_3digits = re.compile(r'(?<=\d)\d{3}(?!\d)')
def intcomma(value):
    segments,last_endoffset=[],len(value)
    while last_endoffset > 3:
        digit_group = re_3digits.search(value,0,last_endoffset)
        if not digit_group:
            break
        segments.append(value[digit_group.start():last_endoffset])
        last_endoffset=digit_group.start()
    if not segments:
        return value
    if last_endoffset:
        segments.append(value[:last_endoffset])
    return ','.join(reversed(segments))

def intcomma_recurs(value):
    """
    Converts an integer to a string containing commas every three digits.
    For example, 3000 becomes '3,000' and 45000 becomes '45,000'.
    """
    new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', str(value))
    if value == new:
        return new
    else:
        return intcomma(new)

@contextmanager
def timed(save_time_func):
    begin=time.time()
    try:
        yield
    finally:
        save_time_func(time.time()-begin)

def testset_xsimple(func):
    func('5')

def testset_simple(func):
    func('567')

def testset_onecomma(func):
    func('567890')

def testset_complex(func):
    func('-1234567.024')

def testset_average(func):
    func('-1234567.024')
    func('567')
    func('5674')

if __name__ == '__main__':
    print 'Test results:'
    for test_data in ('5','567','1234','1234.56','-253892.045'):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs):
            print func.__name__,test_data,func(test_data)
    times=[]
    def overhead(x):
        pass
    for test_run in xrange(1,4):
        for func in (intcomma,intcomma_noregex,intcomma_noregex_reversed,intcomma_recurs,overhead):
            for testset in (testset_xsimple,testset_simple,testset_onecomma,testset_complex,testset_average):
                for x in xrange(1000): # prime the test
                    testset(func)
                with timed(lambda x:times.append(((test_run,func,testset),x))):
                    for x in xrange(50000):
                        testset(func)
    for (test_run,func,testset),_delta in times:
        print test_run,func.__name__,testset.__name__,_delta

Y aquí están los resultados de la prueba:

intcomma 5 5
intcomma_noregex 5 5
intcomma_noregex_reversed 5 5
intcomma_recurs 5 5
intcomma 567 567
intcomma_noregex 567 567
intcomma_noregex_reversed 567 567
intcomma_recurs 567 567
intcomma 1234 1,234
intcomma_noregex 1234 1,234
intcomma_noregex_reversed 1234 1,234
intcomma_recurs 1234 1,234
intcomma 1234.56 1,234.56
intcomma_noregex 1234.56 1,234.56
intcomma_noregex_reversed 1234.56 1,234.56
intcomma_recurs 1234.56 1,234.56
intcomma -253892.045 -253,892.045
intcomma_noregex -253892.045 -253,892.045
intcomma_noregex_reversed -253892.045 -253,892.045
intcomma_recurs -253892.045 -253,892.045
1 intcomma testset_xsimple 0.0410001277924
1 intcomma testset_simple 0.0369999408722
1 intcomma testset_onecomma 0.213000059128
1 intcomma testset_complex 0.296000003815
1 intcomma testset_average 0.503000020981
1 intcomma_noregex testset_xsimple 0.134000062943
1 intcomma_noregex testset_simple 0.134999990463
1 intcomma_noregex testset_onecomma 0.190999984741
1 intcomma_noregex testset_complex 0.209000110626
1 intcomma_noregex testset_average 0.513000011444
1 intcomma_noregex_reversed testset_xsimple 0.124000072479
1 intcomma_noregex_reversed testset_simple 0.12700009346
1 intcomma_noregex_reversed testset_onecomma 0.230000019073
1 intcomma_noregex_reversed testset_complex 0.236999988556
1 intcomma_noregex_reversed testset_average 0.56299996376
1 intcomma_recurs testset_xsimple 0.348000049591
1 intcomma_recurs testset_simple 0.34600019455
1 intcomma_recurs testset_onecomma 0.625
1 intcomma_recurs testset_complex 0.773999929428
1 intcomma_recurs testset_average 1.6890001297
1 overhead testset_xsimple 0.0179998874664
1 overhead testset_simple 0.0190000534058
1 overhead testset_onecomma 0.0190000534058
1 overhead testset_complex 0.0190000534058
1 overhead testset_average 0.0309998989105
2 intcomma testset_xsimple 0.0360000133514
2 intcomma testset_simple 0.0369999408722
2 intcomma testset_onecomma 0.207999944687
2 intcomma testset_complex 0.302000045776
2 intcomma testset_average 0.523000001907
2 intcomma_noregex testset_xsimple 0.139999866486
2 intcomma_noregex testset_simple 0.141000032425
2 intcomma_noregex testset_onecomma 0.203999996185
2 intcomma_noregex testset_complex 0.200999975204
2 intcomma_noregex testset_average 0.523000001907
2 intcomma_noregex_reversed testset_xsimple 0.130000114441
2 intcomma_noregex_reversed testset_simple 0.129999876022
2 intcomma_noregex_reversed testset_onecomma 0.236000061035
2 intcomma_noregex_reversed testset_complex 0.241999864578
2 intcomma_noregex_reversed testset_average 0.582999944687
2 intcomma_recurs testset_xsimple 0.351000070572
2 intcomma_recurs testset_simple 0.352999925613
2 intcomma_recurs testset_onecomma 0.648999929428
2 intcomma_recurs testset_complex 0.808000087738
2 intcomma_recurs testset_average 1.81900000572
2 overhead testset_xsimple 0.0189998149872
2 overhead testset_simple 0.0189998149872
2 overhead testset_onecomma 0.0190000534058
2 overhead testset_complex 0.0179998874664
2 overhead testset_average 0.0299999713898
3 intcomma testset_xsimple 0.0360000133514
3 intcomma testset_simple 0.0360000133514
3 intcomma testset_onecomma 0.210000038147
3 intcomma testset_complex 0.305999994278
3 intcomma testset_average 0.493000030518
3 intcomma_noregex testset_xsimple 0.131999969482
3 intcomma_noregex testset_simple 0.136000156403
3 intcomma_noregex testset_onecomma 0.192999839783
3 intcomma_noregex testset_complex 0.202000141144
3 intcomma_noregex testset_average 0.509999990463
3 intcomma_noregex_reversed testset_xsimple 0.125999927521
3 intcomma_noregex_reversed testset_simple 0.126999855042
3 intcomma_noregex_reversed testset_onecomma 0.235999822617
3 intcomma_noregex_reversed testset_complex 0.243000030518
3 intcomma_noregex_reversed testset_average 0.56200003624
3 intcomma_recurs testset_xsimple 0.337000131607
3 intcomma_recurs testset_simple 0.342000007629
3 intcomma_recurs testset_onecomma 0.609999895096
3 intcomma_recurs testset_complex 0.75
3 intcomma_recurs testset_average 1.68300008774
3 overhead testset_xsimple 0.0189998149872
3 overhead testset_simple 0.018000125885
3 overhead testset_onecomma 0.018000125885
3 overhead testset_complex 0.0179998874664
3 overhead testset_average 0.0299999713898

Números italianos: mil separadores es un '.'

Lo resolví de esta manera ... para un dictonario

from random import randint

voci = {
    "immobilizzazioni": randint(200000, 500000),
    "tfr": randint(10000, 25000),
    "ac": randint(150000, 200000),
    "fondo": randint(10500, 22350),
    "debiti": randint(150000, 250000),
    "ratei_attivi": randint(2000, 2500),
    "ratei_passivi": randint(1500, 2600),
    "crediti_v_soci": randint(10000, 30000)
}


testo_rnd2 = """Nell’azienda Hypermax S.p.a. di Bologna le immobilizzazioni valgono {immobilizzazioni:,} €, i debiti per TFR sono pari a {tfr:,} €, l’attivo circolante è di {ac:,} euro, il fondo rischi ed oneri ha un importo pari a {fondo:,} euro, i debiti sono {debiti:,} €, i ratei e risconti attivi sono pari a {ratei_attivi:,} euro, i ratei e risconti passivi sono pari a {ratei_passivi:,} euro. I crediti verso i soci sono pari a {crediti_v_soci:,} euro."""

print(testo_rnd2)

fuera: le immobilizzazioni valgono 419.168 & # 8364 ;. i debiti por TFR sono pari a 13.255 & # 8364 ;. l & # 8217; attivo circolante & # 232; di 195.443 euros. Il fondo rischi ed oneri ha importo pari a 13.374 euros. i debiti sono 180.947 & # 8364 ;. Califico e risconti attivi sono pari a 2.271 euros. Califico e risconti pasivi sono pari a 1.864 euros. Acredito verso i soci sono pari a 17.630 euros.

Aquí hay otra variante que usa una función de generador que funciona para enteros:

def ncomma(num):
    def _helper(num):
        # assert isinstance(numstr, basestring)
        numstr = '%d' % num
        for ii, digit in enumerate(reversed(numstr)):
            if ii and ii % 3 == 0 and digit.isdigit():
                yield ','
            yield digit

    return ''.join(reversed([n for n in _helper(num)]))

Y aquí hay una prueba:

>>> for i in (0, 99, 999, 9999, 999999, 1000000, -1, -111, -1111, -111111, -1000000):
...     print i, ncomma(i)
... 
0 0
99 99
999 999
9999 9,999
999999 999,999
1000000 1,000,000
-1 -1
-111 -111
-1111 -1,111
-111111 -111,111
-1000000 -1,000,000

Solo subclase long (o float, o lo que sea). Esto es muy práctico, porque de esta manera todavía puede usar sus números en operaciones matemáticas (y, por lo tanto, el código existente), pero todos se imprimirán bien en su 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

Prefiero la solución basada en la configuración regional para proyectos reales, pero creo que el enfoque con el uso de la asignación de sectores debe mencionarse aquí:

def format_money(f, delimiter=',', frac_digits=2):

    negative_fix = int(f < 0)

    s = '%.*f' % (frac_digits, f)
    if len(s) < 5 + frac_digits + negative_fix:
        return s

    l = list(s)
    l_fix = l[negative_fix:]
    p = len(l_fix) - frac_digits - 5
    l_fix[p::-3] = [i + delimiter for i in l_fix[p::-3]]

    return ''.join(l[:negative_fix] + l_fix)

Gist with doctests está aquí: https://gist.github.com/ei-grad / b290dc761ae253af69438bbb94d82683

Para carrozas:

float(filter(lambda x: x!=',', '1,234.52'))
# returns 1234.52

Para entradas:

int(filter(lambda x: x!=',', '1,234'))
# returns 1234

Si no desea depender de ninguna biblioteca externa:

 s = str(1234567)
 print ','.join([s[::-1][k:k+3][::-1] for k in xrange(len(s)-1, -1, -3)])

Esto funciona solo para enteros no negativos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top