Facile bella stampa di galleggianti in python?


93

Ho un elenco di galleggianti. Se lo faccio semplicemente print, si presenta così:

[9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]

Potrei usare print "%.2f", che richiederebbe un forciclo per attraversare l'elenco, ma poi non funzionerebbe per strutture di dati più complesse. Vorrei qualcosa del tipo (lo sto inventando completamente)

>>> import print_options
>>> print_options.set_float_precision(2)
>>> print [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
[9.0, 0.05, 0.03, 0.01, 0.06, 0.08]

Risposte:


23

È una vecchia domanda ma aggiungerei qualcosa di potenzialmente utile:

So che hai scritto il tuo esempio in liste Python non elaborate, ma se decidi di usare numpyinvece gli array (il che sarebbe perfettamente legittimo nel tuo esempio, perché sembra che tu abbia a che fare con array di numeri), c'è (quasi esattamente) questo comando tu ha detto che hai inventato:

import numpy as np
np.set_printoptions(precision=2)

O ancora meglio nel tuo caso se vuoi ancora vedere tutti i decimali di numeri veramente precisi, ma sbarazzati degli zeri finali, ad esempio, usa la stringa di formattazione %g:

np.set_printoptions(formatter={"float_kind": lambda x: "%g" % x})

Per stampare una sola volta e non modificare il comportamento globale, utilizzare np.array2stringcon gli stessi argomenti di cui sopra.


102

Poiché nessuno l'ha aggiunto, va notato che andando avanti da Python 2.6+ il modo consigliato per eseguire la formattazione di stringhe è con format, per prepararsi per Python 3+.

print ["{0:0.2f}".format(i) for i in a]

La nuova sintassi per la formattazione delle stringhe non è difficile da usare, eppure è abbastanza potente.

Pensavo che pprintpotesse essere qualcosa, ma non ho trovato nulla.


1
Questo era quello che ho usato ma ho aggiunto .replace("'", "")per sbarazzarmi di quelle virgole. str(["{0:0.2f}".format(i) for i in a]).replace("'", "")
Steinarr Hrafn Höskuldsson

Questo produrrà un elenco di stringhe. Nell'output stampato, ogni elemento ha ''intorno. Ad esempio, per a=[0.2222, 0.3333], produrrà ['0.22', '0.33'].
jdhao

Per rimuovere l'apice e le virgole, dovresti usare' '.join([{0:0.2f}".format(i) for i in a])
Neb

78

Una soluzione più permanente è la sottoclasse float:

>>> class prettyfloat(float):
    def __repr__(self):
        return "%0.2f" % self

>>> x
[1.290192, 3.0002, 22.119199999999999, 3.4110999999999998]
>>> x = map(prettyfloat, x)
>>> x
[1.29, 3.00, 22.12, 3.41]
>>> y = x[2]
>>> y
22.12

Il problema con la sottoclasse floatè che interrompe il codice che cerca esplicitamente il tipo di una variabile. Ma per quanto ne so, questo è l'unico problema. E un semplice x = map(float, x)annullamento della conversione in prettyfloat.

Tragicamente, non puoi semplicemente riparare le scimmie float.__repr__perché floatè immutabile.

Se non vuoi sottoclassare float, ma non ti dispiace definire una funzione, map(f, x)è molto più conciso di[f(n) for n in x]


Avrei pensato che ci fosse una soluzione più semplice, ma la tua risposta è chiaramente la migliore, dal momento che sei quasi l'unico a rispondere effettivamente alla mia domanda.
static_rtti

4
È l'unico a rispondere davvero alla tua domanda -edita. Non denigrare chi ha risposto, ma non è possibile chiarire una domanda e poi sminuire il resto dei rispondenti in base alle informazioni su cui stavamo lavorando.
Jed Smith

1
La mia domanda originale diceva che consideravo un ciclo for non una buona soluzione (per me la comprensione di una lista è la stessa, ma sono d'accordo che non fosse chiara). La prossima volta cercherò di essere più chiaro.
static_rtti

2
[f (n) for n in x] è molto più pitonico di map (f, x).
Robert T. McGibbon

2
Non sono necessariamente a favore della sottoclasse float, ma non penso che il controllo del tipo sia un argomento valido. Durante il controllo dei tipi, isinstancedovrebbe essere usato, non l'uguaglianza di type(). Quando è fatto correttamente, una sottoclasse di float verrà comunque conteggiata come un float.
zondo

37

Tu puoi fare:

a = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
print ["%0.2f" % i for i in a]

3
Questo stamperà ['9.00', '0.05', '0.03', '0.01', '0.06', '0.08'] - con virgolette, cosa che di solito non vuoi (preferisco avere un elenco valido di float stampato)
Emile

23

Tieni presente che puoi anche moltiplicare una stringa come "% .2f" (esempio: "% .2f" * 10).

>>> print "%.2f "*len(yourlist) % tuple(yourlist)
2.00 33.00 4.42 0.31 

3
molto elegante! Mi piace
Nathan Fellman

2
-1 terribile hack. Unisci pezzi di stringhe formattati, non in altro modo per favore
u0b34a0f6ae

1
quindi kaizer.se, stai proponendo "" .join (["%. 2f"% x per x nella tua lista]). Devo fare questo tipo di costruzione in Python.
Gregg Lind

sì, lo propongo " ".join("%.2f" % x for x in yourlist)poiché separare la stringa di formato e i valori di interpolazione è molto peggio che usare un brutto idioma Python.
u0b34a0f6ae

È curiosità. Perché la tupla funziona mentre la lista fallisce? Senza "tupla", commette errori. Perché?
Joonho Park,

8
print "[%s]"%", ".join(map(str,yourlist))

Ciò eviterà gli errori di arrotondamento nella rappresentazione binaria quando stampata, senza introdurre un vincolo di precisione fisso (come la formattazione con "%.2f"):

[9.0, 0.053, 0.0325754, 0.0108928, 0.0557025, 0.0793303]

7
l = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]

Python 2:

print ', '.join('{:0.2f}'.format(i) for i in l)

Python 3:

print(', '.join('{:0.2f}'.format(i) for i in l))

Produzione:

9.00, 0.05, 0.03, 0.01, 0.06, 0.08

Non so perché questo non sia più alto. Una soluzione che non si basa su librerie di terze parti!
Fl.pf.

7

L'opzione più semplice dovrebbe essere quella di utilizzare una routine di arrotondamento:

import numpy as np
x=[9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]

print('standard:')
print(x)
print("\nhuman readable:")
print(np.around(x,decimals=2))

Questo produce l'output:

standard:
[9.0, 0.053, 0.0325754, 0.0108928, 0.0557025, 0.0793303]

human readable:
[ 9.    0.05  0.03  0.01  0.06  0.08]

questa è un'ottima risposta
jjz

4

Credo che Python 3.1 li stamperà meglio per impostazione predefinita, senza alcuna modifica del codice. Ma questo è inutile se usi estensioni che non sono state aggiornate per funzionare con Python 3.1


1
Python 3.1 stamperà la rappresentazione decimale più breve che mappa a quel valore float. Ad esempio: >>> a, b = float (1.1), float (1.1000000000000001) >>> a 1.1000000000000001 >>> b 1.1000000000000001 >>> print (a, b) 1.1 1.1
Matt Boehm

4

Le composizioni della lista sono tuoi amici.

print ", ".join("%.2f" % f for f in list_o_numbers)

Provalo:

>>> nums = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999]
>>> print ", ".join("%.2f" % f for f in nums)
9.00, 0.05, 0.03, 0.01

5
Un'espressione del generatore sarebbe ancora meglio: "," .join ("%. 2f"% f per f in list_o_numbers)
efotinis

@efotinis Non li ho ancora aggiunti al mio repertorio, ma hai ragione - è piuttosto sexy.
Jed Smith

1
@Jed: Per favore leggi le FAQ, sezione "Altre persone possono modificare le mie cose ?!": stackoverflow.com/faq . Non tutte le modifiche sono buone, ma questa è stata un vero miglioramento. Forse puoi elencare entrambe le tecniche nella tua risposta e aggiungere una nota sulla differenza?
Stephan202

4

Per controllare il numero di cifre significative , utilizza l'identificatore di formato% g.

Chiamiamo la soluzione di Emile prettylist2f. Ecco quello modificato:

prettylist2g = lambda l : '[%s]' % ', '.join("%.2g" % x for x in l)

Utilizzo:

>>> c_e_alpha_eps0 = [299792458., 2.718281828, 0.00729735, 8.8541878e-12]
>>> print(prettylist2f(c_e_alpha_eps0)) # [299792458.00, 2.72, 0.01, 0.00]
>>> print(prettylist2g(c_e_alpha_eps0)) # [3e+08, 2.7, 0.0073, 8.9e-12]

Se desideri flessibilità nel numero di cifre significative, utilizza invece la formattazione f-string :

prettyflexlist = lambda p, l : '[%s]' % ', '.join(f"{x:.{p}}" for x in l)
print(prettyflexlist(3,c_e_alpha_eps0)) # [3e+08, 2.72, 0.0073, 8.85e-12]

3

Potresti usare i panda.

Ecco un esempio con un elenco:

In: import pandas as P
In: P.set_option('display.precision',3)
In: L = [3.4534534, 2.1232131, 6.231212, 6.3423423, 9.342342423]
In: P.Series(data=L)
Out: 
0    3.45
1    2.12
2    6.23
3    6.34
4    9.34
dtype: float64

Se hai un dict d e vuoi le sue chiavi come righe:

In: d
Out: {1: 0.453523, 2: 2.35423234234, 3: 3.423432432, 4: 4.132312312}

In: P.DataFrame(index=d.keys(), data=d.values())
Out:  
    0
1   0.45
2   2.35
3   3.42
4   4.13

E un altro modo per dare dict a un DataFrame:

P.DataFrame.from_dict(d, orient='index')

2

Innanzitutto, gli elementi all'interno di una collezione stampano la loro riproduzione. dovresti conoscere __repr__e __str__.

Questa è la differenza tra print repr (1.1) e print 1.1. Uniamo tutte quelle stringhe invece delle rappresentazioni:

numbers = [9.0, 0.053, 0.0325754, 0.0108928, 0.0557025, 0.07933]
print "repr:", " ".join(repr(n) for n in numbers)
print "str:", " ".join(str(n) for n in numbers)

NOTA: In Python 2.7, per questo esempio, i risultati della riga "repr" e della riga "str" ​​sono identici.
ToolmakerSteve

2

Mi sono imbattuto in questo problema mentre cercavo di usare pprint per produrre un elenco di tuple di float. Le comprensioni annidate potrebbero essere una cattiva idea, ma ecco cosa ho fatto:

tups = [
        (12.0, 9.75, 23.54),
        (12.5, 2.6, 13.85),
        (14.77, 3.56, 23.23),
        (12.0, 5.5, 23.5)
       ]
pprint([['{0:0.02f}'.format(num) for num in tup] for tup in tups])

All'inizio ho usato le espressioni del generatore, ma pprint ha appena ripreso il generatore ...


2

A partire da Python 3.6, puoi usare le stringhe f:

list_ = [9.0, 0.052999999999999999, 
         0.032575399999999997, 0.010892799999999999, 
         0.055702500000000002, 0.079330300000000006]

print(*[f"{element:.2f}" for element in list_])
#9.00 0.05 0.03 0.01 0.06 0.08

Puoi usare i parametri di stampa mantenendo il codice molto leggibile:

print(*[f"{element:.2f}" for element in list_], sep='|', end='<--')
#9.00|0.05|0.03|0.01|0.06|0.08<--

1

Ho avuto questo problema, ma nessuna delle soluzioni qui ha fatto esattamente quello che volevo (voglio che l'output stampato sia un'espressione Python valida), quindi che ne dici di questo:

prettylist = lambda l : '[%s]' % ', '.join("%.2f" % f for f in l)

Utilizzo:

>>> ugly = [9.0, 0.052999999999999999, 0.032575399999999997,
            0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
>>> prettylist = lambda l : '[%s]' % ', '.join("%.2f" % f for f in l)
>>> print prettylist(ugly)
[9.00, 0.05, 0.03, 0.01, 0.06, 0.08]

(So ​​che .format () dovrebbe essere la soluzione più standard, ma la trovo più leggibile)


0

Sono d'accordo con il commento di SilentGhost, il ciclo for non è poi così male. Puoi ottenere ciò che desideri con:

l = [9.0, 0.052999999999999999, 0.032575399999999997, 0.010892799999999999, 0.055702500000000002, 0.079330300000000006]
for x in l: print "%0.2f" % (x)

3
Sebbene i cicli for non siano brutti, questo utilizzo non è terribilmente pitonico.
Jed Smith

-1

Il codice seguente funziona bene con me.

list = map (lambda x: float('%0.2f' % x), list)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.