2010-07-16 18 views
12

Tengo algunas listas y estructuras más complejas que contienen flotadores. Al imprimirlos, veo los flotadores con muchos dígitos decimales, pero cuando los imprimo, no los necesito todos. Así que me gustaría definir un formato personalizado (por ejemplo, 2 o 3 decimales) cuando se imprimen los flotadores.Cambiar formato de impresión flotante predeterminado

Necesito usar flotadores y no Decimal. Además, no tengo permitido truncar/rodear carrozas.

¿Hay alguna manera de cambiar el comportamiento predeterminado?

Respuesta

7

no está permitido a monkeypatch C tipos, como Ignacio dijo.

Sin embargo, si está muy presionado para hacerlo y sabe algo de C, puede modificar el código fuente del intérprete de Python, y luego recompilarlo en una solución personalizada. Una vez modifiqué uno de los comportamientos estándar para las listas y fue solo un dolor moderado.

que sugieren que encuentre una mejor solución, tal como se acaba de imprimir los flotadores con la notación "%0.2f" printf:

for item in mylist: 
    print '%0.2f' % item, 

o

print " ".join('%0.2f' % item for item in mylist) 
+0

El problema es que he flotado dentro de listas, y cuando imprimo (lista) no tengo control sobre eso. (Esto se aplica también para otros objetos, por cierto). Modificar el código fuente es factible porque conozco C, pero no es exactamente lo que estaba pensando. Gracias. – AkiRoss

+0

@AkiRoss: Entonces, lo que desea corregir es la lista, no los flotadores ... –

+0

@AkiRoss, si desea más control, simplemente imprima los artículos individualmente. –

3

No, porque eso requeriría la modificación de float.__str__(), pero no se permite el monopaquete de tipos C. Utilice la interpolación de cadenas o el formato en su lugar.

+0

En realidad, sería necesario modificar 'float .__ repr__'.'str' solo usa 12 dígitos significativos. – dan04

1
>>> a = 0.1 
>>> a 
0.10000000000000001 
>>> print a 
0.1 
>>> print "%0.3f" % a 
0.100 
>>> 

Desde el Python docs, repr(a) daría 17 dígitos (como se ve con solo escribir a desde el modo interactivo, pero str(a) (se realiza automáticamente cuando lo imprima) se redondea a 12.

Editar: La mayoría solución básica truco ... Usted tiene que usar su propia clase, sin embargo, por lo que ... sí.

>>> class myfloat(float): 
...  def __str__(self): 
...    return "%0.3f" % self.real 
>>> b = myfloat(0.1) 
>>> print repr(b) 
0.10000000000000001 
>>> print b 
0.100 
>>> 
0

de actualización a Python 3.1. No usa más dígitos de los necesarios.

Python 3.1.2 (r312:79147, Apr 15 2010, 15:35:48) 
[GCC 4.4.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> 0.1 
0.1 
+0

Ya lo estoy usando. Ese no es el punto, pero gracias por la propina. – AkiRoss

-1

Si está utilizando el lenguaje C, puede utilizar #define o "%*.*f" de hacer eso, por ejemplo,

printf("%*.*f",4,2,variable); 
+1

Está utilizando explícitamente etiquetas de python, por lo que no está utilizando C – Bruce

2

Me encontré con este problema hoy, y se me ocurrió una solución diferente. Si le preocupa cómo se ve cuando se imprime, puede reemplazar el objeto de archivo stdout por uno personalizado que, cuando se invoca a write(), busca cualquier elemento que parezca flotante y lo reemplaza con su propio formato para ellos.

class ProcessedFile(object): 

    def __init__(self, parent, func): 
     """Wraps 'parent', which should be a file-like object, 
     so that calls to our write transforms the passed-in 
     string with func, and then writes it with the parent.""" 
     self.parent = parent 
     self.func = func 

    def write(self, str): 
     """Applies self.func to the passed in string and calls 
     the parent to write the result.""" 
     return self.parent.write(self.func(str)) 

    def writelines(self, text): 
     """Just calls the write() method multiple times.""" 
     for s in sequence_of_strings: 
      self.write(s) 

    def __getattr__(self, key): 
     """Default to the parent for any other methods.""" 
     return getattr(self.parent, key) 

if __name__ == "__main__": 
    import re 
    import sys 

    #Define a function that recognises float-like strings, converts them 
    #to floats, and then replaces them with 1.2e formatted strings. 
    pattern = re.compile(r"\b\d+\.\d*\b") 
    def reformat_float(input): 
     return re.subn(pattern, lambda match: ("{:1.2e}".format(float(match.group()))), input)[0] 

    #Use this function with the above class to transform sys.stdout. 
    #You could write a context manager for this. 
    sys.stdout = ProcessedFile(sys.stdout, reformat_float) 
    print -1.23456 
    # -1.23e+00 
    print [1.23456] * 6 
    # [1.23e+00, 1.23e+00, 1.23e+00, 1.23e+00, 1.23e+00, 1.23e+00] 
    print "The speed of light is 299792458.0 m/s." 
    # The speed of light is 3.00e+08 m/s. 
    sys.stdout = sys.stdout.parent 
    print "Back to our normal formatting: 1.23456" 
    # Back to our normal formatting: 1.23456 

No sirve de nada si sólo está poniendo números en una cadena, pero con el tiempo es probable que desee para escribir esa cadena a algún tipo de archivo en alguna parte, y usted puede ser capaz de envolver que el archivo de la encima del objeto Obviamente, hay un poco de una sobrecarga de rendimiento.

Advertencia de feria: No he probado esto en Python 3, no tengo idea de si funcionaría.

Cuestiones relacionadas