Wie kann ich verhindern, dass csv.DictWriter() oder writerow() Rundung meiner schwimmt?
Ich habe ein Wörterbuch, das ich schreiben will in eine csv-Datei, aber die schwimmt im Wörterbuch abgerundet sind, wenn ich Sie Schreibe in die Datei. Ich will, dass die maximale Genauigkeit.
Wo kommt die Rundung auftreten, und wie kann ich es verhindern?
, Was ich Tat
Folgte ich dem DictWriter Beispiel hier und ich bin mit Python 2.6.1 auf Mac (10.6 - Snow Leopard).
# my import statements
import sys
import csv
Hier ist, was mein Wörterbuch (d) enthält:
>>> d = runtime.__dict__
>>> d
{'time_final': 1323494016.8556759,
'time_init': 1323493818.0042379,
'time_lapsed': 198.85143804550171}
Die Werte sind in der Tat schwimmt:
>>> type(runtime.time_init)
<type 'float'>
Dann richte ich mein writer und schreiben der header und Werte:
f = open(log_filename,'w')
fieldnames = ('time_init', 'time_final', 'time_lapsed')
myWriter = csv.DictWriter(f, fieldnames=fieldnames)
headers = dict( (n,n) for n in fieldnames )
myWriter.writerow(headers)
myWriter.writerow(d)
f.close()
Aber wenn ich einen Blick in die Ausgabe-Datei, bekomme ich gerundete zahlen (D. H., unbelegt):
time_init,time_final,time_lapsed
1323493818.0,1323494016.86,198.851438046
< EOF >
- Nicht Teil des Problems, aber in Python 2.x immer öffnen von csv-Dateien in Binär - Modus (
'rb'
oder'wb'
) - Vielen Dank für das heads-up und für die überprüfung meine Frage. +1
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sieht es aus wie csv ist mit schweben.__str__ eher als schweben.__repr__:
Blick auf die csv-Quelle, das erscheint als ein hardwired Verhalten. Eine Problemumgehung ist die Besetzung aller float-Werte, um Ihre repr bevor csv bekommt es. Verwenden Sie so etwas wie:
d = dict((k, repr(v)) for k, v in d.items())
.Hier gearbeitet-Beispiel:
Dieser code erzeugt die folgende Ausgabe:
Einer verfeinerten Ansatz kümmern wird nur Ersatz für Schwimmer:
Hinweis, ich habe gerade das Problem gelöst für Py2.7.3, also sollte es kein problem sein in der Zukunft. Sehen http://hg.python.org/cpython/rev/bf7329190ca6
Es ist ein bekannter bug^H^H^Hfeature. Nach die docs:
"""... der Wert None ist geschrieben wie eine leere Zeichenfolge. [snip] Alle nicht-string-Daten sind stringified mit str (), bevor Sie geschrieben."""
Verlassen Sie sich nicht auf die Standard-Konvertierungen. Verwenden
repr()
für Schwimmer.unicode
Objekte benötigen eine spezielle Handhabung; siehe Handbuch. Überprüfen Sie, ob der Verbraucher der Datei akzeptieren Sie die Standard-format vondatetime.x
Objekte für x in (datetime, date, time, timedelta).Update:
Für float-Objekte
"%f" % value
ist nicht ein guter Ersatz fürrepr(value)
. Das Kriterium ist, ob der Verbraucher kann die Datei reproduzieren der ursprünglichen float-Objekt.repr(value)
gewährleistet dies."%f" % value
nicht.Beachten Sie, dass in der oben genannten, es erscheint durch Einsicht in die Saiten produziert, dass keiner der
%f
Fällen gearbeitet. Vor 2.7, Pythonrepr
immer verwendet 17 signifikante Dezimalstellen. In 2.7 wurde dies geändert, um mit die minimale Anzahl vor Ziffern an, die noch garantiertfloat(repr(v)) == v
. Der Unterschied ist nicht einem Rundungsfehler.Beachten Sie die verbesserte
repr()
Ergebnisse in der ersten Spalte oben.Update 2 in Reaktion auf Kommentar """Und vielen Dank für die info auf Python 2.7. Leider bin ich beschränkt auf 2.6.2 (läuft auf dem Ziel-Rechner, die nicht aktualisiert werden kann). Aber ich werde dies im Hinterkopf behalten für zukünftige Skripte. """
Ist es egal.
float('0.3333333333333333') == float('0.33333333333333331')
produziertTrue
auf allen Versionen von Python. Dies bedeutet, dass Sie schreiben konnte Sie Ihre Datei auf 2,7 und es Lesen würden, die gleich auf 2.6, oder Umgekehrt. Es ist keine änderung in der Genauigkeit, wasrepr(a_float_object)
produziert.Funktioniert es, aber es ist wahrscheinlich nicht die beste/effizienteste Weg:
%f
Formatierung verwendet nur 6 Dezimalstellen in einigen Fällen. "Sieht aus wie" ist irreführend; siehe meine aktualisierte Antwort.