2010-07-16 15 views
12

Ho alcune liste e strutture più complesse contenenti float. Quando li stampo, vedo i float con molte cifre decimali, ma quando stampo, non ho bisogno di tutti loro. Quindi vorrei definire un formato personalizzato (ad esempio 2 o 3 decimali) quando i float vengono stampati.Cambiare il formato di stampa float predefinito

Ho bisogno di usare float e non decimale. Inoltre, non sono autorizzato a troncare/arrotondare i float.

C'è un modo per modificare il comportamento predefinito?

risposta

7

non è consentito a tipi di C monkeypatch, come ha detto Ignacio.

Tuttavia, se si è terribilmente pressati a farlo e si conosce un C, è possibile modificare manualmente il codice sorgente dell'interprete Python, quindi ricompilarlo in una soluzione personalizzata. Una volta ho modificato uno dei comportamenti standard per le liste ed era solo un dolore moderato.

vi suggerisco di trovare una soluzione migliore, come ad esempio la stampa solo i carri con la notazione "%0.2f" printf:

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

o

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

Il problema è che ho fluttuato all'interno degli elenchi, e quando stampo (elenco) non ne ho il controllo. (Questo vale anche per altri oggetti, btw). Modificare il codice sorgente è fattibile come so C, ma non è esattamente quello che stavo pensando. Grazie. – AkiRoss

+0

@AkiRoss: Quindi ciò che si desidera correggere è l'elenco, non i float ... –

+0

@AkiRoss, se si desidera un maggiore controllo è sufficiente stampare gli elementi singolarmente. –

3

No, perché ciò richiederebbe la modifica di float.__str__(), ma non è consentito il monkeypatch dei tipi C. Utilizzare invece l'interpolazione o la formattazione delle stringhe.

+0

In realtà, sarebbe necessario modificare 'float .__ repr__'.'str' usa solo 12 cifre significative. – dan04

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

Dal Python docs, repr(a) darebbe 17 cifre (come si vede semplicemente digitando a al prompt interattivo, ma str(a) (eseguito automaticamente quando si stampa) giri per 12.

Edit: La maggior parte soluzione di base mod ... Devi usare la propria classe, però, quindi ... 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

Aggiornamento a Python 3.1. Non usa più cifre del necessario.

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

già utilizzato. Non è questo il punto, ma grazie per il suggerimento. – AkiRoss

-1

Se si sta utilizzando il linguaggio C, è possibile utilizzare #define o "%*.*f" per farlo, ad esempio,

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

Usa esplicitamente i tag python, quindi non sta usando C – Bruce

2

Mi sono imbattuto in questo problema oggi e ho trovato una soluzione diversa. Se sei preoccupato di come appare una volta stampato, puoi sostituire l'oggetto file stdout con uno personalizzato che, quando viene chiamato write(), cerca qualsiasi cosa che assomiglia a float e li sostituisce con il tuo formato per loro.

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 

Non va bene se si sta solo mettendo i numeri in una stringa, ma alla fine probabilmente si vorrà scrivere la stringa a una sorta di file da qualche parte, e si può essere in grado di avvolgere il file con il sopra l'oggetto. Ovviamente c'è un po 'di overhead delle prestazioni.

Fair warning: non ho provato questo in Python 3, non ho idea se avrebbe funzionato.

Problemi correlati